Секреты LINQ. Автогенерируемые свойства. Инициализаторы объектов и коллекций, страница 5

static void Inform(string name)    // Этот метод является будущим заданием делегата

{

Console.WriteLine(Environment.ExpandEnvironmentVariables(name));

}

Добавьте в Main код вызова метода Inform с помощью generic-делегата Action<string> и выполните код.

Action<string> s = Inform;

s("%SystemDrive%");

¨  Шаблон Action<T> делегата s настроен на сигнатуру void (string).

¨  Обращение к делегату: s ("%SystemDrive%"); эквивалентно вызову Inform ("%SystemDrive%");.

Следующая версия шаблона Action<> позволяет создавать делегаты, которые способны вызывать функции с двумя параметрами.

public delegate void Action<T1, T2> (T1 arg1, T2 arg2);

Типы параметров настраиваются с помощью параметров шаблона T1 и T2. Рассмотрим пример. Добавьте в класс Program метод SaveImage, сигнатура которого соответствует типу Action<string, byte[]>.

static void SaveImage(string file, byte[] data)

{

File.WriteAllBytes(file, data);

}

Добавьте в Main код вызова метода SaveImage с помощью generic-делегата типа Action<string, byte[]>.

byte[] img = File.ReadAllBytes(@"C:\WINDOWS\Web\Wallpaper\Windows XP.jpg");

Action<string, byte[]> save = SaveImage;

save(@"C:\Test.jpg", img);

Библиотека System.Core.dll содержит определение еще двух делегатных типов из семейства Action<>. Они соответствуют void-методам с тремя и четырьмя параметрами. Типы параметров, как и ранее, задаются с помощью параметров шаблона. Семейство шаблонов Action<> позволяет создавать делегаты для вызова void-методов, имеющих от 0 до 4 параметров. Этот шаблон охватывает довольно широкий класс методов, которые могут встретиться на практике.

Семейство generic-делегатов вида Func<>

В System.Core.dll также определено семейство делегатных типов Func<>, которое соответствует произвольным методам, возвращающим значение произвольного типа. Как и в случае с Action<>, существует несколько объявлений этого делегатного типа. Они отличаются количеством входных параметров (от одного, до четырех). Рассмотрим объявление этого делегатного типа для функций с одним параметром.

public delegate TResult Func <T,TResult> (T arg);

Указанное объявление generic-делегата сообщает программисту и компилятору о том, что Func является типом указателей, способных адресовать любую функцию, которая на входе требует переменную типа T и возвращает переменную типа TResult. Как видите, последний (второй) параметр шаблона (TResult) определяет тип возвращаемого функцией значения, а первый — тип входного параметра функции.

При объявлении делегата (указателя) программист задает конкретные типы (T и TResult), после чего компилятор настраивает шаблон на эти типы, то есть, генерирует делегат (код вызова метода). Имея делегатный тип (сигнатуру делегата), можно определить новый делегат (указатель), например так:

Func<double, double> pFunc = Math.Sin;   // pFunc указывает на метод, вычисляющий синус

Console.WriteLine (pFunc(1.5)); // Вызов метода с помощью pFunc. Результат: 0,997494986604054

pFunc = Math.Sqrt;     // Теперь pFunc указывает на метод, вычисляющий квадратный корень

Console.WriteLine (pFunc(1.5)); // Результат: 1,22474487139159

Указателю pFunc можно присвоить имя (вы помните, что имя — это адрес) функции Sin или функции Sqrt. Указателю можно присвоить имя (адрес) любой другой функции с сигнатурой double (double).

Делегатный тип Func описывает любую функцию с одним параметром типа T, которая возвращает переменную типа TResult. С помощью делегата Func <Person, int> p, настроенного на типы Person и int, можно вызвать несколько разных методов, например: int GetHash (Person), или int GetPersonID (Person).

В пространстве имен System определены еще несколько делегатных типов вида Func<>. Например.

delegate TResult Func <T, U, TResult> (T a, U b);