为什么以下在委托中使用协方差的示例无法编译?

时间:2015-02-28 14:57:10

标签: c# generics delegates covariance

我定义了以下委托类型。一个返回一个字符串,一个返回一个对象:

delegate object delobject();
delegate string delstring();

现在考虑以下代码:

delstring a = () => "foo";
delobject b = a; //Does not compile!

为什么作业无效?

我不明白。返回字符串的方法应该被安全地视为返回对象的方法(因为字符串是对象)。


在C#4.0中,以下示例有效。我使用Func<TResult>泛型类型:

而不是使用委托
Func<string> a = () => "foo";
Func<object> b = a; //Perfectly legal, thanks to covariance in generics

另外:如果我以这种方式改写它,它可以工作:

delobject b = () => a();

但这与我最初想要的不一样。现在我创建了一个调用另一个方法的新方法。

这不仅仅是一项任务,如本例所示:

delint a = () => 5;
delobject b = a; //Does not work, but this is OK, since "int" is a value type.
delobject b = () => a(); //This will box the integer to an object.

3 个答案:

答案 0 :(得分:11)

委托类型仍然是具体的对象类型。当你写

delegate object delobject();
delegate string delstring();

然后没有&#34;是&#34;两个委托类型之间的关系。您只是创建了两种不同的类型。

就像

一样
class A { public int i; };
class B { public int i; };

AB之间没有隐式或显式转换,即使没有任何可能A与{B无关{1}},反之亦然。

Func中的共同和逆转意味着该具体代表类型的作者已决定Func<string>可被视为Func<object>,但这是作者的作者委托类型可以决定,就像我的班级B的作者可以决定是否从A派生出来更有意义。

可以做的事情是添加一个间接级别而不创建其他方法:

delstring a = () => "foo";
delobject b = new delobject(a); // or equivalently, a.Invoke

答案 1 :(得分:5)

Func的类型参数标记为inout,因此您可以像这样将这些类型分配给另一个。这就是泛型中的方差

您的delobjectdelstring是不同的类型,它们不是变体,因此您无法将其分配给另一个。但是delobject你可以指定一个返回派生类型的处理程序,这就是委托中方差的含义。

答案 2 :(得分:3)

Delegates (MSDN)

  

在方法重载的上下文中,方法的签名不包括返回值。但在代理的上下文中,签名确实包含了返回值。换句话说,方法必须与委托具有相同的返回类型

由于返回类型完全匹配(即object != string),因此分配无效。

所以你可以拥有

delstring a = () => "foo"; // compiles
delobject b = a;           // does not compile
delobject c = () => "foo"; // compiles

正如您所指出的那样,Func使用out协同工作,而代表则不会。