Разъяснение о делегатах - PullRequest
       1

Разъяснение о делегатах

3 голосов
/ 20 октября 2011

Что делает приведенный ниже код? Я думаю, что указатель будет изменен на метод умножения. Но что здесь делает "+ =". Я в замешательстве.

    delegate int calc(int a , int b);

    static void Main(string[] args)
    {
        calc c = new calc(Add);
        c += new calc(Multiply);
        Console.WriteLine(c(3, c(4, 2)));
        Console.Read();
    }

    public static int Add(int a, int b)
    {
        return (a + b);
    }

    public static int Multiply(int a, int b)
    {
        return (a * b);
    }

Ответы [ 4 ]

4 голосов
/ 20 октября 2011

Операторы + и + =

Аналогично тому, как вы используете оператор + для добавления значений, вы можете использовать оператор += для добавления и присвоения одного и того же значения.

Пример применения этих операторов к int s:

int a = 5;
a += 7; // a is now 12
a = a + 11;
Console.WriteLine(a);

24

Объединение делегатов

Как уже упоминалось в AVD, вы используете операторы + и += для объединения делегатов .

Когда вы применяете эти операторы к делегатам, вы не выполняете математическую «сумму» или «сумму и присваиваете», как мой пример с int s. Вместо этого вы изменяете список методов, вызываемых при вызове делегата.

Из этой статьи:

Делегаты могут быть объединены так, что при вызове делегата вызывается целый список методов - потенциально с разными целями

Поэтому, когда вы добавляете / комбинируете делегатов, вы в конечном итоге вызываете несколько методов.

Если вы измените свой код на:

public static int Add(int a, int b)
{
    Console.WriteLine("From Add");
    return (a + b);
}

public static int Multiply(int a, int b)
{
    Console.WriteLine("From Multiply");
    return (a * b);
}

Тогда вы увидите этот вывод при запуске программы:

От Добавить
От умножения
От Добавить
От умножения
24

Это потому что:

  • Вы объединили делегатов Add и Multiply, поэтому оба звонят, когда вы звоните c(x, y)
  • Multiply - последний делегат, которого вы добавили в эту цепочку делегатов
  • Вы звоните c(x, y) дважды. Это похоже на то, как если бы вы звонили: Multiply(3, Multiply(4, 2))

Возвращаемые значения от объединенных делегатов

Этот пункт о последнем делегате, которого вы добавили в цепочку, также упоминается в статье:

Если тип делегата объявлен для возврата значения (т. Е. Он не объявлен с возвращаемым типом void) и вызван объединенный экземпляр делегата, то значение, возвращаемое этим вызовом, будет возвращено последним простым делегатом в списке .

Последний метод, который вы добавили в цепочку, был Multiply, поэтому все остальные возвращаемые значения отбрасываются, и при вызове c(x, y).

используется только возвращаемое значение из Multiply.

Вы можете увидеть это в своей программе. 3 * 4 * 2 равно 24, что является выводом вашей программы. Ни один из ваших звонков на Add не повлияет на конечный результат.

2 голосов
/ 20 октября 2011

+ = похоже на добавление нескольких вызовов к объекту делегата. Поскольку это многоадресные делегаты, вы можете добавить несколько вызовов к одному делегату. Чтобы присоединиться к делегату, вам нужны новые объекты делегата. И это то, что делалось во второй строке.

Это похоже на,

CalcDelegate C1, C2;
C1 = new CalcDelegate(Add);
C2 = new CalcDelegate(Multiply);
C1 = C1 + C2;
0 голосов
/ 20 октября 2011

Вы можете рассматривать делегатов как нечто среднее между типами значений (например, int или double) и массивами адресов методов.

Вы знаете, что если вы напишите этот код:

var x = 5;
var y = x + 2;
y += 3;

Затем впоследствии x == 5 & y == 10, хотя y имел промежуточное значение 7, оно было "выброшено", когда произошло окончательное присвоение.

Совершенно ясно, окончательное значениеy не 3.

В своем коде вы написали это:

calc c = new calc(Add);
c += new calc(Multiply);

Как и в случае y, окончательное значение c не Multiply.Это действительно так:

c == { Add, Multiply }

Когда вы затем вызываете что-то вроде c(4, 2), вы фактически вызываете обоих Add & Multiply, и потому что делегат возвращает значение, которое вывернуть только окончательное значение делегата - в данном случае от Multiply - и вот почему создается впечатление, что «указатель» изменился на метод Multiply.

Вы можете попробовать добавить этот код перед тем, каквызовите c:

c -= new calc(Multiply);

, и это фактически вернет c к этому:

c == { Add }

И именно поэтому делегаты ведут себя как массивы адресов методов.

Теперь, если вы измените методы Add & Multiply, чтобы они выглядели так:

public static int Add(int a, int b)
{
    Console.WriteLine("Add({0}, {1})", a, b);
    return (a + b);
}

public static int Multiply(int a, int b)
{
    Console.WriteLine("Multiply({0}, {1})", a, b);
    return (a * b);
}

, вы сможете наблюдать за звонками по мере их возникновения.Ваш оригинальный код работает так:

Add(4, 2)
Multiply(4, 2)
Add(3, 8)
Multiply(3, 8)
24

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

0 голосов
/ 20 октября 2011

Это называется Объединение делегатов .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...