Разница между передачей конструктору делегата группы методов и экземпляра другого делегатаC#

Место общения программистов C#
Anonymous
Разница между передачей конструктору делегата группы методов и экземпляра другого делегата

Сообщение Anonymous »

В C# делегаты обычно создаются неявно компилятором из групп методов, лямбда-выражений и анонимных делегатов. Однако вы также можете создать их явно, вызвав конструктор делегата. Например, предположим, что у меня есть метод Foo:

Код: Выделить всё

public void Foo(object? sender, EventArgs e)
{
Console.WriteLine("Foo");
}
Теперь давайте создадим два делегата EventHandler на основе Foo:

Код: Выделить всё

var x = new EventHandler(Foo); // Delegate from method group Foo
var y = new EventHandler(x);   // Delegate from another EventHandler delegate
Мне интересно узнать разницу между созданием делегата из группы методов и созданием делегата из другого делегата. Судя по результатам моего расследования, созданные экземпляры предоставляют тот же результат вызова:

Код: Выделить всё

x.Invoke(null, null); // "Foo"
y.Invoke(null, null); // "Foo"
Однако в этом случае экземпляры делегата не равны:

Код: Выделить всё

ReferenceEquals(x, y); // false, as expected, these are different instances
Equals(x, y);          // false
x.Equals(y);           // false
Это немного неожиданно, учитывая, что делегаты, созданные из одной и той же группы методов, в .Net равны.

Код: Выделить всё

var x1 = new EventHandler(Foo);
var y1 = new EventHandler(Foo);
ReferenceEquals(x1, y1); // false, as expected, these are different instances
Equals(x1, y1);          // false
Насколько я вижу, делегаты x и y имеют разное свойство Target. Для делегата x, созданного из группы методов Foo, Target является экземпляром класса, объявляющего Foo. Для делегата y, созданного из экземпляра делегата x, Target на самом деле является x.
Мне кажется, что делегаты, созданные из других экземпляров делегата, работают для них как что-то вроде оболочки. Однако мне не удалось найти описание этого в документации (было бы здорово дать ссылку на что-нибудь, описывающее это).
Мне хотелось бы знать, как это на самом деле работает и почему существует разница в значениях Target. Есть ли сценарий, в котором эта разница необходима?

Вернуться в «C#»