Язык программирования C#9 и платформа .NET5. Страница 242
static string SumToString(int x, int y){ return (x + y).ToString();}Вызовите эти методы:
Func<int, int, int> funcTarget = Add;int result = funcTarget.Invoke(40, 40);Console.WriteLine("40 + 40 = {0}", result);Func<int, int, string> funcTarget2 = SumToString;string sum = funcTarget2(90, 300);Console.WriteLine(sum);С учетом того, что делегаты
Action<>Func<>Action<>Func<>На заметку! Делегаты
Action<>Func<>Итак, первоначальный экскурс в типы делегатов окончен. Теперь давайте перейдем к обсуждению связанной темы — ключевого слова
eventПонятие событий C#
Делегаты — довольно интересные конструкции в том плане, что позволяют объектам, находящимся в памяти, участвовать в двустороннем взаимодействии. Тем не менее, прямая работа с делегатами может приводить к написанию стереотипного кода (определение делегата, определение необходимых переменных-членов, создание специальных методов регистрации и отмены регистрации для предохранения инкапсуляции и т.д.).
Более того, во время применения делегатов непосредственным образом как механизма обратного вызова в приложениях, если вы не определите переменную-член типа делегата в классе как закрытую, тогда вызывающий код будет иметь прямой доступ к объектам делегатов. В таком случае вызывающий код может присвоить переменной-члену новый объект делегата (фактически удаляя текущий список функций, которые подлежат вызову) и, что даже хуже, вызывающий код сможет напрямую обращаться к списку вызовов делегата. В целях демонстрации создайте новый проект консольного приложения по имени
PublicDelegateProblemCarCarDelegatenamespace PublicDelegateproblem{ public class Car { public delegate void CarEngineHandler(string msgForCaller);<b> // Теперь это член public!</b> public CarEngineHandler ListOfHandlers; // Просто вызвать уведомление Exploded. public void Accelerate(int delta) { if (ListOfHandlers != null) { ListOfHandlers("Sorry, this car is dead..."); } } }}Обратите внимание, что у вас больше нет закрытых переменных-членов с типами делегатов, инкапсулированных с помощью специальных методов регистрации. Поскольку эти члены на самом деле открытые, вызывающий код может получить доступ прямо к переменной-члену
ListOfHandlersCarEngineHandlerusing System;using PublicDelegateProblem;Console.WriteLine("***** Agh! No Encapsulation! *****\n");// Создать объект Car.Car myCar = new Car();// Есть прямой доступ к делегату!myCar.ListOfHandlers = CallWhenExploded;myCar.Accelerate(10);// Теперь можно присвоить полностью новый объект...// что в лучшем случае сбивает с толку.myCar.ListOfHandlers = CallHereToo;myCar.Accelerate(10);// Вызывающий код может также напрямую вызывать делегат!myCar.ListOfHandlers.Invoke("hee, hee, hee...");Console.ReadLine();static void CallWhenExploded(string msg){ Console.WriteLine(msg);}static void CallHereToo(string msg){ Console.WriteLine(msg);}Открытие доступа к членам типа делегата нарушает инкапсуляцию, что не только затруднит сопровождение кода (и отладку), но также сделает приложение уязвимым в плане безопасности! Ниже показан вывод текущего примера:
***** Agh! No Encapsulation! *****Sorry, this car is dead...Sorry, this car is dead...