Функции обратного вызова являются важной частью программирования Windows. Если у вас есть опыт программирования на C или C++, вы использовали обратные вызовы во многих API-интерфейсах Windows. После добавления ключевого слова AddressOf в VB разработчики и разработчики могут воспользоваться преимуществами API, которые когда-то были ограничены. Функции обратного вызова на самом деле являются указателями на вызовы методов, также известными как указатели функций, которые являются очень мощной функцией программирования. .NET реализует концепцию указателей функций в форме делегатов. Их особенность заключается в том, что, в отличие от указателей на функции C, делегаты .NET являются типобезопасными. Это показывает, что указатель функции в C — это всего лишь указатель на единицу хранения. Мы не можем сказать, на что на самом деле указывает этот указатель, не говоря уже о параметрах и типах возвращаемых значений. Как описано в этой главе, делегаты .NET работают как типобезопасная операция. Ниже мы узнаем, как .NET использует делегаты как способ реализации событий.
1. Доверие
Если вы хотите передать метод другому методу, вам нужно использовать делегат. Чтобы понять, что они означают, взгляните на следующий код:
int я = int.Parse("99");
Мы привыкли передавать данные в качестве параметров методам, как показано в примере выше. Итак, передача другого метода методу звучит немного странно. Иногда операция, выполняемая методом, выполняется не над данными, а над другим методом, более сложным. Мы не знаем, что такое второй метод во время компиляции. Эту информацию можно получить только во время выполнения, поэтому нам нужно передать второй метод в качестве параметра первому методу. Вот несколько примеров. :
1. Запуск потоков. В C# вы можете указать компьютеру запускать определенные новые последовательности выполнения параллельно. Эта последовательность называется потоком. Используйте метод Start() для экземпляра накопленного System.Threading.Thread, чтобы начать выполнение потока. Если вы хотите сообщить компьютеру о начале новой последовательности выполнения, вы должны указать, где эта последовательность должна быть выполнена. Компьютеру необходимо предоставить подробную информацию о методе для начала выполнения, т. е. метод Thread.Start() должен принимать параметр, который определяет метод, который будет вызываться потоком.
2. Общие классы библиотек ------ Существует множество библиотек, содержащих код для выполнения различных стандартных задач. Эти библиотеки обычно автономны. Таким образом, при написании библиотеки вы будете знать, как выполнить задачу. Но иногда задачи содержат и подзадачи. Только клиентский код, использующий библиотеку, знает, как выполнять эти подзадачи. Например, напишите класс, который принимает массив объектов и сортирует их по возрастанию. Однако часть процесса сортировки включает повторное использование двух объектов в массиве и их сравнение, чтобы определить, какой из них должен быть первым. Если бы вы писали класс, который должен был иметь возможность сортировать любой массив объектов, вы не могли бы заранее сообщить компьютеру, как следует сравнивать объекты. Клиентский код, который обрабатывает массивы объектов в классе, также должен сообщать классу, как сравнивать объекты, подлежащие сортировке. Другими словами, клиентский код должен передать классу определенные детали, которые сделают это подходящим.
3. События ------ обычно уведомляют код о том, какие события произошли. Программирование графического пользовательского интерфейса в основном связано с обработкой событий. Когда происходит событие, среда выполнения должна знать, какой метод следует выполнить. Для этого необходимо передать метод, обрабатывающий время, в качестве параметра делегата. Они будут обсуждаться позже.
Ранее мы установили правило, согласно которому имена методов иногда передаются в качестве аргументов другим методам. Ниже необходимо указать, как завершить этот процесс. Самый простой способ — передать имя метода в качестве параметра. Например, в предыдущем примере потока предположим, что запускается новый поток и существует метод EntryPoint(), в котором поток начинает работать.
недействительный EntryPoint()
{
//делаем все, что нужно новому потоку
}
Вы также можете использовать следующий код, чтобы начать выполнение нового потока:
Поток NewThread = новый поток();
Thread.Start(EntryPoint); //НЕПРАВИЛЬНО;
На самом деле это очень простой способ, который используется в некоторых языках, таких как C и C++ (в C и C++ параметр EntryPoint является указателем на функцию).
Но такой прямой подход может вызвать некоторые проблемы, такие как безопасность типов. При объектно-ориентированном программировании методы редко существуют изолированно. Обычно перед вызовом их необходимо связать с экземпляром класса. И этот метод не учитывает этот вопрос. Таким образом, .NET Framework синтаксически не допускает такого прямого подхода. Если вы хотите передать метод, вы должны инкапсулировать детали метода в новый тип объекта — делегат. Делегаты — это особый тип объектов. Особенность заключается в том, что все объекты, которые мы определили ранее, содержат данные, тогда как делегаты содержат только детали методов.
-