I couldn't find the + operator in Reflector under Delegate
or MulticastDelegate
.
I'm trying to figure out how this doesn't need a cast:
Action a = () => Console.WriteLine("A");
Action b = () => Console.WriteLine("B");
Action c = a + b;
But this does:
Action a = () => Console.WriteLine("A");
Action b = () => Console.WriteLine("B");
Action c = (Action)MulticastDelegate.Combine(a, b);
In the first sample is the cast just done under the covers?
Delegates in . NET are multicast delegates. Regardless of whether you choose to attach zero or one or several handlers to them, they are still multicast delegates.
The "-" operator can be used to remove a component delegate from a composed delegate.
C# - Action Delegate Action is a delegate type defined in the System namespace. An Action type delegate is the same as Func delegate except that the Action delegate doesn't return a value. In other words, an Action delegate can be used with a method that has a void return type.
+=
and -=
is implemented at the language level (i.e. with compiler help) with known delegate types, so it doesn't need a cast, whereas Delegate.Combine
is just an ordinary (non-generic) method with Delegate
return type, so it needs a cast.
Taking the following example:
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();
}
}
Then looking at it with 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();
}
}
Seems that they do the exact same thing, just C# is providing some syntactic sugar in the first test.
In the first sample is the cast just done under the covers?
Yes, you can say that!
The Combine
method was written in .NET 1 where no generic C# existed. The formal return type of Combine
therefore had to be Delegate
:
public static Delegate Combine(Delegate a, Delegate b)
{
...
}
But the method still returns an Action
when both a
and b
are Action
. And yes, a
and b
are required to have the same runtime type.
Please don't write MulticastDelegate.Combine
as Combine
is a static
method defined by the System.Delegate
class. Therefore say Delegate.Combine
, that's less confusing.
Detour:
The current version of C# and Combine
has problems with contravariant delegate types. Consider the following:
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
Now, suppose some future version of the framework introduced a generic Combine
method:
public static TDel Combine<TDel>(TDel a, TDel b) where TDel : Delegate
{
// use typeof(TDel) to figure out type of new "sum" delegate
}
and suppose C# was changed such that +
was translated into a call to the new generic Combine<>
method, then contravariance and delegate combination would be fixed! I guess they tell us they have higher priorities, but still.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With