为什么使用Delegate.Combine需要强制转换但使用+运算符不?
我在Delegate
或MulticastDelegate
下的Reflector中找不到+运算符。
我想弄清楚这不需要演员如何:
Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = a + b;
但这样做:
Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = (Action)MulticastDelegate.Combine(a, b);
在第一个样品中是刚刚在封面下完成的铸造?
以下面的例子为例:
class Program { static void Main(string[] args) { Test1(); Test2(); } public static void Test1() { Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = a + b; c(); } public static void Test2() { Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = (Action)MulticastDelegate.Combine(a, b); c(); } }
然后用ILSpy查看它:
internal class Program { private static void Main(string[] args) { Program.Test1(); Program.Test2(); } public static void Test1() { Action a = delegate { Console.WriteLine("A"); }; Action b = delegate { Console.WriteLine("B"); }; Action c = (Action)Delegate.Combine(a, b); c(); } public static void Test2() { Action a = delegate { Console.WriteLine("A"); }; Action b = delegate { Console.WriteLine("B"); }; Action c = (Action)Delegate.Combine(a, b); c(); } }
似乎他们完全一样,只是C#在第一次测试中提供了一些语法糖。
+=
和-=
在语言级别(即使用编译器帮助)实现,具有已知的委托类型,因此它不需要强制转换,而Delegate.Combine
只是一个具有Delegate
返回类型的普通(非generics)方法,所以它需要演员。
在第一个样品中是刚刚在封面下完成的铸造?
是的,你可以这么说!
Combine
方法是用.NET 1编写的,其中不存在通用的C#。 因此,正式返回类型的Combine
必须是Delegate
:
public static Delegate Combine(Delegate a, Delegate b) { ... }
但是当a
和b
都是Action
时,该方法仍返回Action
。 是的, a
和b
需要具有相同的运行时类型。
请不要编写MulticastDelegate.Combine
因为Combine
是System.Delegate
类定义的static
方法。 因此,请说Delegate.Combine
,这不那么令人困惑。
车辆改道:
当前版本的C#和Combine
存在逆变委托类型的问题。 考虑以下:
Action doSomethingToString; // will be assigned below Action a = cloneable => { Console.WriteLine("I'm cloning"); cloneable.Clone(); } Action b = convertible => { Console.WriteLine("I'm converting"); convertible.ToInt32(CultureInfo.InvariantCulture); } Action aStr = a; // OK by contravariance of Action, aStr and a reference same object Action bStr = b; // OK by contravariance of Action, bStr and b reference same object doSomethingToString = aStr + bStr; // throws exception doSomethingToString("42"); // should first clone "42" then convert "42" to Int32
现在,假设该框架的未来版本引入了一个通用的Combine
方法:
public static TDel Combine(TDel a, TDel b) where TDel : Delegate { // use typeof(TDel) to figure out type of new "sum" delegate }
并假设C#被更改为+
被转换为对新通用Combine<>
方法的调用,然后将修复逆向和委托组合! 我猜他们告诉我们他们有更高的优先级,但仍然。
它使用“运算符重载”完成,您可以在自己的对象中执行此操作。
public class MyObject { public string Property { get; set; } public MyObject(string property) { this.Property = property; } public static MyObject operator +(MyObject a1, MyObject a2) { return new MyObject(a1.Property + a2.Property); } } MyObject o1 = new MyObject("Hello"); MyObject o2 = new MyObject(" World!"); MyObject o3 = o1 + o2;
结果:o3.Property =“Hello World!”
所以我假设框架在后台执行这样的事情
public static Action operator +(Action a1, Action a2) { return (Action)MulticastDelegate.Combine(a1,a2); }