Использование многоадресного делегата для объединения функций

Мой вопрос подробно описан в следующем коде - причина, по которой я прошу об этом, заключается в том, что я экспериментирую с делегатами:

//create the delegate          
delegate int del(int x);

class Program {


    static void Main(string[] args) {

        Program p;
        p = new Program();

        del d = p.a;
        d += p.b;
        d += p.c;
        d += p.d;
        d += p.e;
        Console.WriteLine(d(10)); //<<was hoping it would be 10+2+3+4+5+6

        Console.WriteLine("press [enter] to exit");
        Console.ReadLine();
    }

    private int a(int x) { Console.WriteLine("a is called"); return x + 2; }
    private int b(int x) { Console.WriteLine("b is called"); return x + 3; }
    private int c(int x) { Console.WriteLine("c is called"); return x + 4; }
    private int d(int x) { Console.WriteLine("d is called"); return x + 5; }
    private int e(int x) { Console.WriteLine("e is called"); return x + 6; }

} 

16 возвращается....

enter image description here

Все функции запускаются, так как различные сообщения "a вызывается" и т.д. все печатаются в console, но возвращается только сумма, возвращаемая из последней функции e - я предполагаю, что в фоновом режиме они возвращается, но затем перезаписывается?

Ответ 1

Когда в вашем вопросе есть делегат multicast, например d, возвращаемое значение является возвращаемым значением из метода last списка вызовов d.

В общем случае для многоадресных делегатов наиболее естественно использовать возвращаемый тип void.

У компилятора не было возможности догадаться, что вы надеялись на 10+2+3+4+5+6. Вы не указали его нигде.

Вы можете изменить свой тип делегата на:

delegate void del(int xToAdd, ref int sum);

Тогда ваш метод a, например, должен выглядеть следующим образом:

private void a(int x, ref int sum) { Console.WriteLine("a is called"); sum += x + 2; }

Затем экземпляр делегата multicast d вызывается следующим образом:

int sum = 0;
d(10, ref sum);
Console.WriteLine(sum);

Надеюсь, это поможет.

Ответ 2

Это не то, как обратные типы обрабатываются для делегатов. Что произойдет, так это то, что все обработчики будут выполняться независимо друг от друга, и тогда один будет выбран случайным образом (технически это обработчик, который был подписан последним, но вы не должны полагаться на это), чтобы вернуть вызывающему абоненту который вызвал делегата.

Я бы очень отговаривал вас от использования события (вы рассматриваете этот делегат как событие), у которого есть возвращаемое значение. Поведение практически никогда не бывает желательным. Если вы хотите получить возвращаемое значение, имеет смысл убедиться, что ваш делегат всегда сопоставляется с одной функцией, не более, не менее.

Что касается фактического создания желаемого результата, хотя существует ряд подходов, вам лучше будет обслуживаться более традиционная коллекция делегатов:

List<Func<int, int>> functions = new List<Func<int, int>>();
//populate

int result = functions.Aggregate(10, (total, func) => func(total));