6

The article states the following: http://msdn.microsoft.com/en-us/library/dd799517.aspx

Variance does not apply to delegate combination. That is, given two delegates of types Action<Derived> and Action<Base> (Action(Of Derived) and Action(Of Base) in Visual Basic), you cannot combine the second delegate with the first although the result would be type safe. Variance allows the second delegate to be assigned to a variable of type Action<Derived>, but delegates can combine only if their types match exactly.

Action<B> baction = (taret) => { Console.WriteLine(taret.GetType().Name); };
Action<D> daction = baction;
Action<D> caction = baction + daction;

In the above code baction and daction take different parameters. But still I am able to combine them. What am I missing?

TIA.

Rick Sladkey
  • 33,988
  • 6
  • 71
  • 95
Paramesh
  • 371
  • 1
  • 3
  • 8
  • In your example, `baction` and `daction` are references to the same object. Therefore `baction.GetType() == daction.GetType()` certainly, because it's the same instance. Problem arises when the two delegate objects are distinct and have different runtime types. Now, _before_ .NET 4.0, for every delegate object the runtime type and the compiletime type agreed, because delegates were (sealed types and) invariant. But in .NET 4.0 and C# 4, and later, a compiletime `Action` could runtime be `Action`, `Action`, `Action>`, and so on. – Jeppe Stig Nielsen Nov 13 '12 at 09:18
  • Close: [event-and-delegate-contravariance-in-net-4-0-and-c-sharp-4-0](http://stackoverflow.com/questions/1120688/event-and-delegate-contravariance-in-net-4-0-and-c-sharp-4-0) – nawfal Jul 07 '14 at 19:16

1 Answers1

10

The documentation is not clear, I agree.

The problem is that the runtime types of two combined delegates must match. Which means that there are scenarios where the compile time types match, but the runtime types do not.

Consider for example:

Func<string> f1 = ()=>"";
Func<object> f2 = ()=>null;
Func<object> f3 = f1; // legal in C# 4 because of covariance
Func<object> f4 = f2 + f3;

That's legal at compile time; you're adding two delegates of the same compile-time type. But at runtime it will fail because the runtime requires that the runtime types exactly match.

This is an unfortunate hole in the CLR type system. I'm hoping we can get it fixed some day, but no promises.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 3
    You diplomatically failed to point out that the part that is working now is the part that _you_ were responsible for. – Rick Sladkey May 20 '11 at 00:18
  • 1
    Am I correct in thinking that part of the difficulty is that there isn't necessarily a way of inferring the best type? Both Action> and Action> derive from Action>, and one could certainly write code which, given T and two delegates deriving from Action>, would produce an Action> which performed both actions sequentially. Given an Action> and Action>, however, there would be no way for the system to know without being told that the combined delegate should be an Action>. – supercat Aug 24 '11 at 20:42
  • 1
    @supercat: first off, just to be precise: Action> *derives from* System.MulticastDelegate. It is *implicitly convertible via reference conversion* to Action>. Nit-pickiness aside, yes, you have identified a genuine problem here. – Eric Lippert Aug 24 '11 at 22:17
  • 2
    @Eric Lippert: Point taken on derivation versus convertibility. In some ways, I wish delegates were an interface rather than class type; such a design would, however, be useless without generics, and by the time generics were added to .net 2.0, delegates were already well established. If delegates were an interface type, something like a closure would only require the creation of one object instance rather than two. I wonder what the broader implications of such a design would have been? – supercat Aug 24 '11 at 23:36
  • @EricLippert why is it required that runtime types should match? What could go wrong if calling `f4` is to merely execute `f2` followed by `f1` and return result of `f1`? – nawfal Jul 07 '14 at 19:15
  • 2
    @nawfal: It's not a *logical* problem, it is an *implementation* problem. Basically, the code in the CLR that deals with delegate combinations does not handle these sorts of covariant scenarios well. – Eric Lippert Jul 07 '14 at 20:48