8

Let say, I have a MulticastDelegate that implements generic delegate and contains several calls:

Func<int> func = null;
func += ( )=> return 8;
func += () => return 16;
func += () => return 32;

Now this code will return 32:

int x = func(); // x=32

I would like to know if there exists (or better I should ask why it doesn't exist!) the C# language feature using which is possible to get the access to results of all delegate's invocations, that means to get the list ({8,16,32})?

Of course it's possible to do the same using .NET framework routines. Something like this will do the work:

public static List<TOut> InvokeToList<TOut>(this Func<TOut> func)
{
    var returnValue = new List<TOut>();
    if (func != null)
    {
        var invocations = func.GetInvocationList();
        returnValue.AddRange(invocations.Select(@delegate => ((Func<TOut>) @delegate)()));
    }
    return returnValue;
}

But I can't get out from the system that there should be the better way, at least without casting (really, why MulticastDelegate is not generic when delegates are)?

Roman Pokrovskij
  • 9,449
  • 21
  • 87
  • 142
  • 2
    'really, why MulticastDelegate is not generic when delegates are' MulticastDelegate has been in the framework since 1.1, which means when it was coded there wasn't any generics available. –  Jun 20 '11 at 12:56

3 Answers3

6

No, there isn't a better way - when you invoke a multicast delegate, the result is just the result of the final delegate. That's what it's like at the framework level.

Multicast delegates are mostly useful for event handlers. It's relatively rare to use them for functions like this.

Note that Delegate itself isn't generic either - only individual delegate types can be generic, because the arity of the type can change based on the type. (e.g. Action<T> and Action<T1, T2> are unrelated types really.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • MulticastDelegate is abstract so am I right to understand that concrete delegate like Action "somewhere inside" produce inherited class (child of MulticastDelegate)? Then why it is impossible to add the new method GetTypedInvocations to return not Delegate[] but Action[] ? – Roman Pokrovskij Jun 22 '11 at 09:41
  • @Roman: Yes, each specific type could add its own method of that kind - although it would need to create the relevant array etc. – Jon Skeet Jun 22 '11 at 13:09
3

You can accomplish what you want if you don't use a Func<int>, but an Action which takes a method as parameter which processes the return values. Here is a small example:

    static Action<Action<int>> OnMyEvent=null;

    static void Main(string[] args)
    {
        OnMyEvent += processResult => processResult(8);
        OnMyEvent += processResult => processResult(16);
        OnMyEvent += processResult => processResult(32);

        var results = new List<int>();
        OnMyEvent(val => results.Add(val));

        foreach (var v in results)
            Console.WriteLine(v);

    }
Doc Brown
  • 19,739
  • 7
  • 52
  • 88
  • I now get what I want with Listof delegates (to escape all stuff with "GetInvocations"), but your sample gives me additional ideas. Thank you. Nice way of thinking. – Roman Pokrovskij Jun 22 '11 at 09:39
1

There is no way to get a) exceptions b) return values from delegates, only by sniffing into result list. Another way is just to have list of delegates and manage it manually.

Andrey
  • 59,039
  • 12
  • 119
  • 163