我只能用"as"来施放逆变代表

rob*_*rob 28 c# generics casting .net-4.0 contravariance

我正在尝试施放逆变委托但由于某种原因我只能使用"as"运算符.

interface MyInterface { }
delegate void MyFuncType<in InType>(InType input);

class MyClass<T> where T : MyInterface
{
    public void callDelegate(MyFuncType<MyInterface> func)
    {
        MyFuncType<T> castFunc1 = (MyFuncType <T>) func; //Error
        MyFuncType<T> castFunc2 = func as MyFuncType<T>; 
        MyFuncType<T> castFunc3 = func is MyFuncType<T> ? (MyFuncType<T>)func : (MyFuncType<T>)null; //Error
    }
}
Run Code Online (Sandbox Code Playgroud)

castFunc2工作正常,但castFunc1和castFunc3导致错误:

Cannot convert type 'delegateCovariance.MyFuncType<myNamespace.MyInterface>' to myNamespace.MyFuncType<T>'
Run Code Online (Sandbox Code Playgroud)

上为运营商MSDN文章指出,castFunc2和castFunc3"等价于"所以我不明白怎么只有一个可能会导致错误.另一部令我困惑的是将MyInterface从接口更改为类可以消除错误.

任何人都可以帮我理解这里发生了什么?谢谢!

Jos*_*eld 15

添加一个约束,使T必须是一个类.

class MyClass<T> where T: class, MyInterface
Run Code Online (Sandbox Code Playgroud)

这为编译器提供了足够的信息来知道T是可转换的.您也不需要显式转换.

差异仅适用于参考类型.T被允许是没有约束的值类型,这破坏了编译器证明T与逆变量兼容的能力.

第二个语句起作用的原因是因为as实际上可以执行空转换.例如:

class SomeClass { }
interface SomeInterface { }
static void Main(string[] args)
{
   SomeClass foo = null;
   SomeInterface bar = foo as SomeInterface;
}
Run Code Online (Sandbox Code Playgroud)

Foo显然不能直接转换为SomeInterface,但它仍然成功,因为仍然可以进行空转换.对于大多数情况,您的MSDN参考可能是正确的,但生成的IL代码非常不同,这意味着它们从技术角度来看根本不同.