Реализация групповых вызовов
Напомним, что делегаты .NET наделены возможностью
public class Car {
// Добавление элемента в список вызовов.
public void OnAboutToBlow(AboutToBlow clientMethod) {almostDeadList += clientMethod;}
public void OnExploded(Exploded clientMethod) {explodedList += clientMethod;}
…
}
Теперь вызывающая сторона может зарегистрировать несколько целевых объектов.
class Program {
static void Main(string[] args) {
Car c1 = new Car("SlugBug", 100, 10);
// Регистрация множества обработчиков событий.
c1.OnAboutToBlow(new Car.AboutToBlow(CarAboutToBlow));
c1.OnAboutToBlow(new Car.AboutToBlow(CarlsAlmostDoomed));
c1.OnExploded(new Car.Exploded(CarExploded));
…
}
// Car будет вызывать эти методы.
public static void CarAboutToBlow(string msg) {Console.WriteLine (msg);}
public static void CarIsAlmostDoomed(string msg) {Console.WriteLine("Важное сообщение от Car: {0}", msg);}
public static void CarExploded(string msg) {Console.WriteLine(msg);}
}
В программном воде CIL операция += преобразуется в вызов статического метода Delegate.Combine (можно было бы вызвать Delegate.Combine непосредственно, но операция += предлагает более простую альтернативу). Взгляните, например, на CIL-представление метода OnAboutToBlow.
.method public hidebysig instance void OnAboutToBlow
.maxstack 8
ldarg.0
dup
ldfld class CarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass CarDelegate.Car/AboutToBlow
stfld class СarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ret
}
Класс Delegate определяет также статический метод Remove, который позволит вызывающей стороне динамически удалять элементы из списка вызовов. Легко догадаться, что в C# разработчики могут для этого использовать перегруженную операцию -=. Чтобы предоставить вызывающей стороне возможность не привязываться к обозначениям AboutToBlow и Exploded, можно добавить в тип Car следующие вспомогательные методы (обратите внимание на операцию -=).
public class Car {
// Удаление элемента из списка вызовов.
public void RemoveAboutToBlow(AboutToBlow clientMethod) {almostDeadList -= clientMethod;}
public void RemoveExploded(Exploded clientMethod) {explodedList -= clientMethod;}
...
}
Здесь синтаксис -= тоже выступает в качестве простого сокращения для вызова статического метода Delegate.Remove, что доказывается следующим программным кодом CIL для члена RemoveAboutToBlow типа Car.
.method public hidebysig instance void RemoveAboutToBlow(class CarDelegate.Car/AboutToBlow clientMethod) cil managed {
.maxstack 8
ldarg.0
dup
ldfld class CarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ldarg.1