var persons = new List<Person>
{
new Person(){ Name = "Bale", Birth = new DateTime(1981, 3, 26), Salary = 10000m },
. . .
}
Делегатом называется объект делегатного типа. Такой объект может ссылаться на метод (указывать на функцию в пределах какого-то класса). Объявления, начинающиеся словом delegate, декларируют делегатные типы (не делегаты). Они лишь задают сигнатуры методов (правила их использования), которые могут быть вызваны с помощью делегата. Говорят, что они задают сигнатуры возможных заданий делегатов. Сигнатурой метода называются правила его вызова, а именно: тип возвращаемого им значения и список типов его параметров.
В пространстве имен System (в сборке System.Core) появились встроенные делегатные типы: Action и Func, которые соответствует наиболее типичним сигнатурам методов. Рассмотрим тип Action. Он определен так:
public delegate void Action(); // Это определение уже существует в System.Core.dll
Любой метод с сигнатурой void() соответствует типу Action. Такой метод не требует аргументов и ничего не возвращает в точку вызова. Рассмотрим пример использования самого простого делегатного типа Action.
class Program
{
static void Inform() { Console.WriteLine(Environment.MachineName); }
static void Say() { Console.WriteLine("I am an Action delegate"); }
static void Main()
{
Action a = Inform;
a();
a += Say;
a();
}
}
¨ Action является делегатным типом, определенным в System.Core.
¨ Переменная a типа Action ссылается на метод Inform. Это возможно потому, что метод Inform соответствует сигнатуре делегатного типа Action. Переменная a является делегатом типа Action.
¨ Обращение к делегату: a(); эквивалентно прямому вызову метода Inform();.
¨ Оператор a += Say; добавляет в список заданий делегата a ссылку на метод Say. Следующий за этим оператором вызов делегата a(); выполнит два действия: Inform и Say. Это происходит потому, что список заданий делегата (InvocationList) теперь содержит две ссылки (на методы Inform и Say), а не одну, как было вначале.
Для иллюстрации сказанного вы можете (в рамках консольного проекта) выполнить следующий код:
class TestDelegate
{
public void Test()
{
Action a = new Action(Say);
a += new Action(Do);
Delegate[] dd = a.GetInvocationList();
Console.WriteLine("Testing Delegate's InvocationList\n");
int i = 0;
foreach (var d in dd)
Console.WriteLine("{0}. Method = {1}, CallingConvention = {2}, Target = {3}, Returns = {4}",
(++i).ToString(), d.Method.Name, d.Method.CallingConvention, d.Target,
d.Method.ReturnType.Name);
}
void Say() { Console.WriteLine("Saying"); }
void Do() { Console.WriteLine("Doing"); }
}
class Program
{
static void Main()
{
new TestDelegate().Test();
}
}
Запустив приложение, вы увидите такой результат.
Testing Delegate's InvocationList
1. Method = Say, CallingConvention = Standard, HasThis, Target = Test.TestDelegate, Returns = Void
2. Method = Do, CallingConvention = Standard, HasThis, Target = Test.TestDelegate, Returns = Void
В пространстве имен System существует делегатный тип Action<T>, который является универсальным (или, родовым — generic). Это означает, что он определяет не одну сигнатуру, а целое семейство (род) сигнатур.
public delegate void Action<T> (T obj); // Это определение тоже существует в System.Core.dll
Объявление Action<T> выглядит почти так же, как и шаблон функций в C++. Только там вместо ключевого слова delegate используется слово template. Доцент В.А. Биллиг предложил переводить термин generic, как универсальный (см. http://www.intuit.ru/department/pl/csharp/).
Можно сказать, что generic-делегаты являются шаблонами ряда сходных сигнатур. Тип Action можно настроить с помощью параметра шаблона T. Например, объявление Action<int> определяет тип указателей на функции с сигнатурой void (int), а объявление Action<Person> настраивает шаблон на сигнатуру void (Person). Рассмотрим пример. Добавьте в класс Program еще одну версию метода Inform.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.