为什么使用Delegate.Combine需要强制转换但使用+运算符不?

时间:2012-11-25 09:10:17

标签: c# delegates

我在DelegateMulticastDelegate下的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);

在第一个样本中是刚刚在封面下完成的演员吗?

4 个答案:

答案 0 :(得分:5)

+=-=在语言级别(即使用编译器帮助)实现,具有已知的委托类型,因此它不需要强制转换,而Delegate.Combine只是普通的具有Delegate返回类型的(非泛型)方法,因此需要强制转换。

答案 1 :(得分:1)

  

在第一个样本中是刚刚在封面下完成的演员吗?

是的,你可以这么说!

{1}}方法是用.NET 1编写的,其中不存在通用的C#。因此,Combine的正式返回类型必须是Combine

Delegate

但当public static Delegate Combine(Delegate a, Delegate b) { ... } Action都为a时,该方法仍会返回b。是的,Actiona需要具有相同的运行时类型。

请不要写b,因为MulticastDelegate.CombineCombine类定义的static方法。因此请说System.Delegate,这不那么令人困惑。

<强>迂回:

当前版本的C#和Delegate.Combine存在逆变委托类型的问题。请考虑以下事项:

Combine

现在,假设该框架的未来版本引入了通用的Action<string> doSomethingToString; // will be assigned below Action<ICloneable> a = cloneable => { Console.WriteLine("I'm cloning"); cloneable.Clone(); } Action<IConvertible> b = convertible => { Console.WriteLine("I'm converting"); convertible.ToInt32(CultureInfo.InvariantCulture); } Action<string> aStr = a; // OK by contravariance of Action<in T>, aStr and a reference same object Action<string> bStr = b; // OK by contravariance of Action<in T>, bStr and b reference same object doSomethingToString = aStr + bStr; // throws exception doSomethingToString("42"); // should first clone "42" then convert "42" to Int32 方法:

Combine

并假设C#已更改,以致public static TDel Combine<TDel>(TDel a, TDel b) where TDel : Delegate { // use typeof(TDel) to figure out type of new "sum" delegate } 被转换为对新通用+方法的调用,然后逆向和委托组合将被修复!我猜他们告诉我们他们有更高的优先级,但仍然。

答案 2 :(得分:1)

采用以下示例:

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#在第一次测试中提供了一些语法糖。

答案 3 :(得分:0)

使用“运算符重载”完成,您可以在自己的对象中执行此操作。

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);
    }