逆变委托输出结果
Contravariant delegate output result
我将 class 层次结构定义为 Object->Fruit->Apple
class Fruit : object{}
class Apple : Fruit{}
并创建了两个静态方法来处理这些 classes
static Fruit FruitProcessor(string fruit)
{
return new Fruit();
}
static Apple ApplesProcessor(string apple)
{
return new Apple();
}
现在我声明一个委托 没有任何 in, out
关键字
public delegate TResult Funk<T, TResult>(T arg);
在我的代码中,我做了以下分配:
Funk<string, Fruit> myFunc;
myFunc = FruitProcessor; // ok, we match signature exactly
myFunc = ApplesProcessor;// this should not work, but works
因为我没有将 TResult 声明为协变 out
参数,所以应该不可能将 ApplesProcessor
分配给 myFunc
委托。但有可能,程序编译和执行时没有任何错误。
如果我更改 Funk 签名以添加 out TResult
public delegate TResult Funk<T, out TResult>(T arg);
一切都和以前一样。
怎么可能?
像这样的情况由通常的隐式转换处理。引用相关的 MSDN 页面 (https://msdn.microsoft.com/en-us/library/dd233060.aspx):
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
// Matching signature.
public static First ASecondRFirst(Second first)
{ return new First(); }
// The return type is more derived.
public static Second ASecondRSecond(Second second)
{ return new Second(); }
// The argument type is less derived.
public static First AFirstRFirst(First first)
{ return new First(); }
// The return type is more derived
// and the argument type is less derived.
public static Second AFirstRSecond(First first)
{ return new Second(); }
// Assigning a method with a matching signature
// to a non-generic delegate. No conversion is necessary.
SampleDelegate dNonGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a non-generic delegate.
// The implicit conversion is used.
SampleDelegate dNonGenericConversion = AFirstRSecond;
// Assigning a method with a matching signature to a generic delegate.
// No conversion is necessary.
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a generic delegate.
// The implicit conversion is used.
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;
简而言之,在您的确切情况下,您正在将非通用委托分配给通用委托 - 在这种情况下始终使用隐式转换。要真正让你的代码失败,你需要做这样的事情:
Funk<string, Fruit> myFunc;
Funk<string, Apple> myAppleFunc = ApplesProcessor;
myFunc = FruitProcessor;
myFunc = myAppleFunc; // Undefined implicit conversion on generic delegate
根据 MSDN,自 .NET 3.5 以来,委托 return 类型的协变和委托输入类型的逆变是隐含的。因此,将 in
和 out
添加到您的委托中没有任何区别。
添加此选项的一个原因是您可以将接受 EventArgs
参数的 "vanilla" 事件处理程序分配给多个事件,这些事件可能使用更具体的 类 派生自 EventArgs
。例如,您可以使用同一个委托来处理按钮单击和按键按下,即使前者传递了 MouseEventArgs
参数而后者传递了 KeyEventArgs
参数。
我将 class 层次结构定义为 Object->Fruit->Apple
class Fruit : object{}
class Apple : Fruit{}
并创建了两个静态方法来处理这些 classes
static Fruit FruitProcessor(string fruit)
{
return new Fruit();
}
static Apple ApplesProcessor(string apple)
{
return new Apple();
}
现在我声明一个委托 没有任何 in, out
关键字
public delegate TResult Funk<T, TResult>(T arg);
在我的代码中,我做了以下分配:
Funk<string, Fruit> myFunc;
myFunc = FruitProcessor; // ok, we match signature exactly
myFunc = ApplesProcessor;// this should not work, but works
因为我没有将 TResult 声明为协变 out
参数,所以应该不可能将 ApplesProcessor
分配给 myFunc
委托。但有可能,程序编译和执行时没有任何错误。
如果我更改 Funk 签名以添加 out TResult
public delegate TResult Funk<T, out TResult>(T arg);
一切都和以前一样。
怎么可能?
像这样的情况由通常的隐式转换处理。引用相关的 MSDN 页面 (https://msdn.microsoft.com/en-us/library/dd233060.aspx):
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
// Matching signature.
public static First ASecondRFirst(Second first)
{ return new First(); }
// The return type is more derived.
public static Second ASecondRSecond(Second second)
{ return new Second(); }
// The argument type is less derived.
public static First AFirstRFirst(First first)
{ return new First(); }
// The return type is more derived
// and the argument type is less derived.
public static Second AFirstRSecond(First first)
{ return new Second(); }
// Assigning a method with a matching signature
// to a non-generic delegate. No conversion is necessary.
SampleDelegate dNonGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a non-generic delegate.
// The implicit conversion is used.
SampleDelegate dNonGenericConversion = AFirstRSecond;
// Assigning a method with a matching signature to a generic delegate.
// No conversion is necessary.
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a generic delegate.
// The implicit conversion is used.
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;
简而言之,在您的确切情况下,您正在将非通用委托分配给通用委托 - 在这种情况下始终使用隐式转换。要真正让你的代码失败,你需要做这样的事情:
Funk<string, Fruit> myFunc;
Funk<string, Apple> myAppleFunc = ApplesProcessor;
myFunc = FruitProcessor;
myFunc = myAppleFunc; // Undefined implicit conversion on generic delegate
根据 MSDN,自 .NET 3.5 以来,委托 return 类型的协变和委托输入类型的逆变是隐含的。因此,将 in
和 out
添加到您的委托中没有任何区别。
添加此选项的一个原因是您可以将接受 EventArgs
参数的 "vanilla" 事件处理程序分配给多个事件,这些事件可能使用更具体的 类 派生自 EventArgs
。例如,您可以使用同一个委托来处理按钮单击和按键按下,即使前者传递了 MouseEventArgs
参数而后者传递了 KeyEventArgs
参数。