Лучшая подборка книг и информации по программированию.Скидка 11%, подарки к заказу и бесплатная доставка!
RSS иконка EMail иконка Домашняя иконка

  • Делегаты.

    Написано 10.05.2010 21:48 devalmor Нет комментариев

    Делегаты лучше всего рассматривать как новый тип объекта в С#, в некотором роде они похожи на классы. Они предназначены для ситуаций, когда требуется передать методы другим методам. Например:

    int I = int.Parse (”99″);

    Здесь вызывается статический метод Parse() из класса System.Int32. Этот метод принимает один параметр — для данного перегруженного варианта — строку. Можно рассматривать ситуацию следующим образом. Метод Parse() производит какие-то действия точно так же, как и другие методы, а именно, он преобразует некоторые данные в int. Однако для того, чтобы использовать этот метод, необходимо указать, что представляют собой значимые данные. Мы делаем это путем передачи параметра (или аргумента). Вот для чего в основном используются аргументы методов — метод берет данные, передаваемые ему в качестве аргументов, и выполняет над ними действия.

    Мы так часто применяем передачу данных в качестве параметров, что даже не задумываемся об этом, и потому идея передачи методов в качестве параметров может звучать несколько странно. Однако возможны случаи, когда метод помимо обработки данных должен делать что-то еще с другим методом, и — усложним ситуацию — во время компиляции неизвестно, что это за метод. Эта информация доступна только во время исполнения, и, следовательно, ее нужно передавать в качестве параметра первому методу. Для пояснения разберем примеры:

    • Запуск потоков. Потоки будут рассматриваться в другой статье. Здесь скажем только, что поток — это последовательность исполнения. Когда приложение начинает работу, оно последовательно выполняет инструкции в статическом методе Main(). В С# можно запустить новую последовательность исполнения, которая будет работать параллельно с той, что уже исполняется. Запускается поток при помощи метода
    • Start() экземпляра одного из базовых классов, System.Threading.Thread. Приложение должно с чего-то начать, и точкой отсчета является Main(). Аналогично, если вы желаете, чтобы компьютер начал новую последовательность исполнения, нужно указать ему, где начать эту последовательность. Необходимо передать ему подробную информацию о методе, в котором начнется исполнение, т.е. Thread.Start() должен принимать параметр, содержащий информацию для этого метода
    • Общие библиотечные классы. Разумеется, существует большое число библиотек, содержащих код для выполнения различных стандартных задач. Обычно библиотеки самодостаточны в том смысле, что вы точно знаете, как выполнить задачу на этапе написания библиотеки. Однако иногда задача содержит в себе некоторую дополнительную задачу, и только клиентский код знает, как ее выполнить. Ниже мы рассмотрим пример сортировки массива объектов. Мы напишем класс, который принимает массив объектов и сортирует их в порядке возрастания. Часть процесса сортировки заключается во взятии двух объектов из массива и их сравнении с целью определения, какой из них должен идти первым. Так как наш класс должен уметь сортировать массивы объектов любого типа, не существует способа, с помощью которого он сможет заранее определить, как производить это сравнение. Клиентский код, который передает нашему классу массив объектов, должен также сообщить классу, как выполнять сравнение для конкретных объектов, которые необходимо отсортировать. Другими словами, клиентский код должен будет передать нашему классу сведения о методе, который можно вызвать для выполнения сравнения.
    • События. События играют важную роль в программировании Windows GUI. Идея состоит в том, что часто требуется информировать некоторый код о том, что произошли те или иные события. Например, при наборе текста в Microsoft Word каждый раз, когда нажимается клавиша, Word должен быть информирован об этом, чтобы он смог выполнить соответствующее действие. (Обычно это означает добавление соответствующей буквы в документ и отображение ее на экране.) Каждый раз при нажатии на клавишу Windows вызывает конкретный метод внутри Word, который осуществляет соответствующее действие, т.е. обрабатывает событие. Для того чтобы Windows могла сделать это, Word в некоторый момент должен сообщить Windows о том, какой метод необходимо вызвать в ответ на нажатие клавиши. Поэтому Word должен вызвать функцию API и передать ей подробности об этом методе. В очередной раз мы видим, что сведения о методе должны быть переданы в качестве параметра. Очевидно, что, программируя на С#, мы будем иметь дело со средой исполнения .NET, а не с Windows, но когда мы приступим к программированию GUI с помощью Windows Forms, то используем те же самые принципы: код должен будет сообщать среде исполнения .NET о том, какие методы обрабатывают какие события. Чтобы сделать это, необходимо будет передавать подробную информацию о методах в качестве параметров другим методам.

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

    void EntryPoint() {
    // выполнение, того, что должен делать новый поток
    }

    Могли бы мы начать новый поток, используя следующий код?

    Thread NewThread = new Thread ();
    Thread.Start(EntryPoint); // Неверно

    Это наиболее простой способ ведения дел, и некоторые языки, например С и С++, именно так и поступают в подобной ситуации (в С и С++ параметр EntryPoint является указателем функции). Кстати говоря, что-то подобное происходит за кулисами в Visual Basic при добавлении обработчиков событий, однако среда исполнения Visual Basic настолько хорошо ограждает вас от деталей происходящего, что вы никогда не догадывались об этом.
    К сожалению, такой прямой подход вызывает некоторые проблемы с безопасностью типов, а также игнорирует тот факт, что в объектно-ориентированном программировании методы редко существуют в изоляции и обычно должны быть ассоциированы с экземпляром класса перед вызовом. Из-за этих проблем С# не разрешает использовать этот подход. Если требуется передавать методы в качестве параметров, сведения о методе необходимо поместить в новый тип объекта — делегат. Делегаты являются особым типом объекта — особым в том смысле, что они содержат не данные, а информацию о методе.


    Оставить комментарий

    Вы должны авторизоваться для отправки комментария.