为什么在泛型方法中没有调用显式操作符

本文关键字:调用 操作符 泛型方法 为什么 | 更新日期: 2023-09-27 17:51:05

我把这个问题提炼成我能想到的最简单的代码示例。为什么显式操作符不从泛型方法调用?

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B b = (B)a; // works as expected
        b = Cast<B>(a);
    }
    static TResult Cast<TResult>(object o)
    {
        return (TResult)o; // throws Invalid Cast Exception
    }
}
class A
{
}
class B
{
    public static explicit operator B(A a)
    {
        return new B();
    }
}

为什么在泛型方法中没有调用显式操作符

因为一个泛型方法有一个 IL集合,基于TResult。它不会对每个调用者产生不同的IL。而泛型TResult 有任何运算符。

还有:这里的运算符需要在objectTResult之间,并且不能定义包含object运算符。

例如:Cast<int>Cast<string>Cast<Guid>都有完全相同的IL。

你可以用dynamic:

作弊
return (TResult)(dynamic)o;

归根结底,implicitexplicit运算符不是true转换运算符;它们完全是编译时的语法糖。代码编译完成后,转换操作符就不再存在了。

编译器看到:

B b = (B) new A();

它表示,"是否存在从AB的本机转换(隐式或显式)?"(例如,如果A扩展了B,则会出现这种情况),或者是少数特殊大小写语言转换之一,例如doubleint(隐式)或intdouble(显式)。

如果没有,则查找用户定义的转换操作符(例如,它只查找AB的定义,而不查找C的定义,以查找从AB的隐式转换)。如果找到了,就将该操作符作为静态方法调用注入,因此代码最终看起来像:

B b = B.SomeAutogneratedName(new A());

这样当你到达运行时它只是在执行另一个方法,一些运行时知道怎么做的事情。实际允许的运行时转换操作符是语言中包含的少数操作符(即从任何基类型到父类型,以及某些基本类型之间的转换操作符)。