Литмир - Электронная Библиотека
A
A

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<>
интенсивно используются во многих важных API-интерфейсах .NET Core, включая инфраструктуру параллельного программирования и LINQ (помимо прочих).

Итак, первоначальный экскурс в типы делегатов окончен. Теперь давайте перейдем к обсуждению связанной темы — ключевого слова

event
языка С#.

Понятие событий C#

Делегаты — довольно интересные конструкции в том плане, что позволяют объектам, находящимся в памяти, участвовать в двустороннем взаимодействии. Тем не менее, прямая работа с делегатами может приводить к написанию стереотипного кода (определение делегата, определение необходимых переменных-членов, создание специальных методов регистрации и отмены регистрации для предохранения инкапсуляции и т.д.).

Более того, во время применения делегатов непосредственным образом как механизма обратного вызова в приложениях, если вы не определите переменную-член типа делегата в классе как закрытую, тогда вызывающий код будет иметь прямой доступ к объектам делегатов. В таком случае вызывающий код может присвоить переменной-члену новый объект делегата (фактически удаляя текущий список функций, которые подлежат вызову) и, что даже хуже, вызывающий код сможет напрямую обращаться к списку вызовов делегата. В целях демонстрации создайте новый проект консольного приложения по имени

PublicDelegateProblem
и добавьте следующую переделанную (и упрощенную) версию класса
Car
из предыдущего примера
CarDelegate
:

namespace 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(&quot;Sorry, this car is dead...&quot;);

      }

    }

  }

}

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

ListOfHandlers
, присвоить ей новые объекты
CarEngineHandler
и вызвать делегат по своему желанию:

using System;

using PublicDelegateProblem;

Console.WriteLine(&quot;***** Agh! No Encapsulation! *****\n&quot;);

// Создать объект Car.

Car myCar = new Car();

// Есть прямой доступ к делегату!

myCar.ListOfHandlers = CallWhenExploded;

myCar.Accelerate(10);

// Теперь можно присвоить полностью новый объект...

// что в лучшем случае сбивает с толку.

myCar.ListOfHandlers = CallHereToo;

myCar.Accelerate(10);

// Вызывающий код может также напрямую вызывать делегат!

myCar.ListOfHandlers.Invoke(&quot;hee, hee, hee...&quot;);

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...

242
{"b":"847442","o":1}