Опубликован: 15.09.2010 | Доступ: свободный | Студентов: 5578 / 969 | Оценка: 3.97 / 3.80 | Длительность: 14:45:00
Лекция 10:

Делегаты и события

< Лекция 9 || Лекция 10: 1234

Операции

Делегаты можно сравнивать на равенство и неравенство. Два делегата равны, если они оба не содержат ссылок на методы или если они содержат ссылки на одни и те же методы в одном и том же порядке. Сравнивать можно даже делегаты различных типов при условии, что они имеют один и тот же тип возвращаемого значения и одинаковые списки параметров.

С делегатами одного типа можно выполнять операции простого и сложного присваивания, например:

Del d1 = new Del( o1.Do );      // o1.Do
Del d2 = new Del( o2.Do );      // o2.Do
Del d3 = d1 + d2;               // o1.Do и o2.Do
d3 += d1;                       // o1.Do, o2.Do и o1.Do
d3 -= d2;                       // o1.Do и o1.Do

Эти операции могут понадобиться, например, в том случае, если в разных обстоятельствах требуется вызывать разные наборы и комбинации наборов методов.

Делегат, как и строка string, является неизменяемым типом данных, поэтому при любом изменении создается новый экземпляр, а старый впоследствии удаляется сборщиком мусора.

Передача делегатов в методы

Поскольку делегат является классом, его можно передавать в методы в качестве параметра. Таким образом обеспечивается функциональная параметризация: в метод можно передавать не только различные данные, но и различные функции их обработки. Функциональная параметризация применяется для создания универсальных методов и обеспечения возможности обратного вызова.

В качестве простейшего примера универсального метода можно привести метод вывода таблицы значений функции, в который передается диапазон значений аргумента, шаг его изменения и вид вычисляемой функции. Пример приведен в листинге 10.3.

using System;
namespace ConsoleApplication1
{
    public delegate double Fun( double x );           // объявление делегата

    class Class1
    {
        public static void Table( Fun F, double x, double b )
        {
            Console.WriteLine( " ----- X ----- Y -----" );
            while (x <= b)
            {
               Console.WriteLine( "| {0,8:0.000} | {1,8:0.000} |", x, F(x));
               x += 1;
            }
            Console.WriteLine( " ---------------------" );
        }

        public static double Simple( double x )
        {
            return 1;
        }
        
        static void Main()
        {
            Console.WriteLine( " Таблица функции Sin " );
            Table( new Fun( Math.Sin ), -2, 2 );

            Console.WriteLine( " Таблица функции Simple " );
            Table( new Fun( Simple ), 0, 3 );
        }
    }
}
Листинг 10.3. Передача делегата через список параметров

Результат работы программы:

Таблица функции Sin
 ----- X ----- Y -----
|   -2,000 |   -0,909 |
|   -1,000 |   -0,841 |
|    0,000 |    0,000 |
|    1,000 |    0,841 |
|    2,000 |    0,909 |
 ---------------------
 Таблица функции Simple
 ----- X ----- Y -----
|    0,000 |    1,000 |
|    1,000 |    1,000 |
|    2,000 |    1,000 |
|    3,000 |    1,000 |
 ---------------------

Обратный вызов (callback) представляет собой вызов функции, передаваемой в другую функцию в качестве параметра. Рассмотрим рисунок 10.1. Допустим, в библиотеке описана функция А, параметром которой является имя другой функции. В вызывающем коде описывается функция с требуемой сигнатурой ( В ) и передается в функцию А. Выполнение функции А приводит к вызову В, то есть управление передается из библиотечной функции обратно в вызывающий код.

Механизм обратного вызова

Рис. 10.1. Механизм обратного вызова

Механизм обратного вызова широко используется в программировании. Например, он реализуется во многих стандартных функциях Windows.

Начиная с Visual Studio 2005, использующей версию 2.0 языка C#, можно применять упрощенный синтаксис для делегатов. Первое упрощение заключается в том, что в большинстве случаев явным образом создавать экземпляр делегата не требуется, поскольку он создается автоматически по контексту. Второе упрощение заключается в возможности создания так называемых анонимных методов — фрагментов кода, описываемых непосредственно в том месте, где используется делегат:

static void Main()
        {
            Console.WriteLine( " Таблица функции Sin " );
            Table( Math.Sin, -2, 2 );                         // упрощение 1

            Console.WriteLine( " Таблица функции Simple " );
            Table( delegate (double x ){ return 1; }, 0, 3 ); // упрощение 2
        }
    }
}

В первом случае экземпляр делегата, соответствующего функции Sin, создается автоматически. Чтобы это могло произойти, список параметров и тип возвращаемого значения функции должны быть совместимы с делегатом. Во втором случае не требуется оформлять простой фрагмент кода в виде отдельной функции Simple, как это было сделано в предыдущем листинге, — код функции оформляется как анонимный метод и встраивается прямо в место передачи.

< Лекция 9 || Лекция 10: 1234
Георгий Кузнецов
Георгий Кузнецов

"Сокрытие деталей реализации называется инкапсуляцией (от слова "капсула"). "

Сколько можно объяснять?!

ИНКАПСУЛЯЦИЯ НЕ РАВНА СОКРЫТИЮ!!!

Инкапсуляция это парадигма ООП, которая ОБЕСПЕЧИВАЕТ СОКРЫТИЕ!!!

НО СОКРЫТИЕМ  НЕ ЯВЛЯЕТСЯ!!! 

Если буровая коронка обеспечивает разрушение породы, то является ли она сама разрушением породы? Конечно нет!

Ольга Притоманова
Ольга Притоманова