我定义了以下委托类型。一个返回字符串,一个返回对象:
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.
委托类型仍然是具体的对象类型。当你写
delegate object delobject();
delegate string delstring();
那么这两种委托类型之间就不存在"是"关系。您只创建了两种不同的类型。
它就像
class A { public int i; };
class B { public int i; };
A
和B
之间没有隐式或显式转换,即使不存在任何可能的A
与B
不具有同等意义,反之亦然。
Func
中的协变和逆变意味着该具体委托类型的作者已经决定Func<string>
可以被视为Func<object>
,但这是委托类型的创作者可以决定的,就像我的类B
的作者可以决定是否从A
派生更有意义一样。
可以做的事情是在不创建额外方法的情况下再添加一个间接级别:
delstring a = () => "foo";
delobject b = new delobject(a); // or equivalently, a.Invoke
Func
的类型参数标记为in
和out
,因此您可以像这样将这些类型一个分配给另一个。这就是泛型中方差的含义。
您的delobject
和delstring
是不同的类型,它们不是变体,因此您不能将一个分配给另一个。但对于delobject
,您可以分配一个返回派生类型的处理程序,这就是委托中差异的含义。
委托(MSDN):
在方法重载的上下文中,方法的签名不包括返回值。但在委托的上下文中,签名确实包含返回值。换句话说,方法必须具有与委托相同的返回类型。
由于返回类型不完全匹配(即object != string
),因此赋值无效。
所以你可以有
delstring a = () => "foo"; // compiles
delobject b = a; // does not compile
delobject c = () => "foo"; // compiles
正如您所指出的,Func使用out
协同工作,而委托则不使用。