使用泛型委托时如何理解逆变?
我正在学习“逆变通用委托”。
我的理解是:
如果没有“in”关键字,我们不知道类型参数是否逆变。
那么委托类型的隐式转换是不允许的。
这是我的代码:
public class Test
{
//public delegate bool FuncDelegate<T>(T t);
public delegate bool FuncDelegate<in T>(T t);
public class BaseClass
{
public int x;
}
public class DerivedClass: BaseClass
{
public int y;
}
static bool BaseFunc(BaseClass bc)
{
if (bc.x > 1)
return false;
else
return true;
}
static bool DerivedFunc(DerivedClass dc)
{
if (dc.y > 1)
return false;
else
return true;
}
public static void Main()
{
FuncDelegate<DerivedClass> genericDerivedFunc = DerivedFunc;
FuncDelegate<BaseClass> genericBaseFunc = BaseFunc;
genericDerivedFunc = genericBaseFunc;
FuncDelegate<DerivedClass> genericDerivedFunc2 = BaseFunc;
}
}
我的问题
/*
This line is valid when declared as: public delegate bool FuncDelegate<in T>(T t);
This line is invalid when declared as: public delegate bool FuncDelegate<T>(T t);
*/
genericDerivedFunc = genericBaseFunc;
这条线与我的理解一致。
/*
This line is always valid.
*/
FuncDelegate<DerivedClass> genericDerivedFunc2 = BaseFunc;
我不明白这一行:
我认为它必须有“in”关键字来指定逆变。
但是可以在没有“in”关键字的情况下完成转换。
回答
请注意这两个作业的右侧之间的区别:
genericDerivedFunc = genericBaseFunc;
genericDerivedFunc2 = BaseFunc;
第一行的右手边是一个委托,因此您将一个委托类型转换为另一个委托类型。这需要方差转换,如 C# 规范中的可用转换中所列:
- ...
- 从任何 reference_type 到接口或委托类型 T,如果它具有到接口或委托类型 T0 的隐式标识或引用转换,并且 T0 可以方差转换为 T。
方差转换需要那些ins 和outs。
但是,在第二行,右侧是一个方法组(方法的名称),因此在第二行中,您实际上是在进行方法组转换。要使此类转换可用,BaseFunc需要与目标委托类型兼容。请注意,这是对方法的要求,而不是对委托类型的要求。要“兼容”。
值得注意的是,方法M与委托类型“兼容”的两个要求D是:
- 对于每个值参数,存在从参数类型 in
D到相应参数类型 in的标识转换或隐式引用转换M。- 存在从 的返回类型
M到 的返回类型的标识或隐式引用转换D。
这些要求使它看起来好像委托类型在其in所有参数和out返回类型上都有修饰符。
基本上,由于 RHS 是非常不同的事物,因此适用不同的规则。