Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В предыдущей статье вы увидели, что создаете определенные типы делегатов с помощью ключевого слова delegate
.
Абстрактный класс Делегат предоставляет инфраструктуру для свободного связывания и вызова. Конкретные типы делегатов становятся гораздо более полезными, используя и обеспечивая строгую типизацию для методов, добавленных в список вызовов объекта делегата. При использовании ключевого delegate
слова и определении конкретного типа делегата компилятор создает эти методы.
На практике это приведет к созданию новых типов делегатов всякий раз, когда требуется другая подпись метода. Эта работа может стать утомительной со временем. Для каждой новой функции требуются новые типы делегатов.
К счастью, это не обязательно. Платформа .NET Core содержит несколько типов, которые можно использовать повторно при необходимости типов делегатов. Это общие определения, которые позволяют объявить настройки, когда необходимо новое объявление методов.
Первым из этих типов является Action тип и несколько вариантов:
public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
// Other variations removed for brevity.
Модификатор in
для аргумента универсального типа рассматривается в статье по ковариации.
Существуют варианты делегата Action
, содержащего до 16 аргументов, таких как Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>.
Важно, чтобы эти определения использовали разные универсальные аргументы для каждого из аргументов делегата: это обеспечивает максимальную гибкость. Аргументы метода могут быть разного типа, но также могут быть и одинакового типа.
Используйте один из Action
типов для любого типа делегата, имеющего тип возвращаемого значения void.
Платформа также включает несколько универсальных типов делегатов, которые можно использовать для типов делегатов, возвращающих значения:
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
// Other variations removed for brevity
Модификатор out
для аргумента результирующих универсальных типов рассматривается в статье по ковариации.
Существуют варианты делегата Func
с до 16 входных аргументов, таких как Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>.
Тип результата всегда указан последним среди параметров типа во всех Func
объявлениях в соответствии с принятым соглашением.
Используйте один из Func
типов для любого типа делегата, возвращающего значение.
Существует также специализированный Predicate<T> тип делегата, который возвращает тест по одному значению:
public delegate bool Predicate<in T>(T obj);
Вы можете заметить, что для любого Predicate
типа существует структурны эквивалентный Func
тип, например:
Func<string, bool> TestForString;
Predicate<string> AnotherTestForString;
Вы можете подумать, что эти два типа эквивалентны. Они нет. Эти две переменные нельзя использовать взаимозаменяемо. Переменная одного типа не может быть назначена другому типу. Система типов C# использует имена определенных типов, а не структуру.
Все эти определения типов делегатов в библиотеке .NET Core должны означать, что вам не нужно определять новый тип делегата для любой новой функции, которая требует делегатов. Эти универсальные определения должны предоставлять все необходимые типы делегатов в большинстве случаев. Можно просто создать экземпляр одного из этих типов с необходимыми параметрами типа. В случае алгоритмов, которые можно сделать универсальными, эти делегаты можно использовать в качестве универсальных типов.
Это должно сэкономить время и свести к минимуму количество новых типов, которые необходимо создать для работы с делегатами.
В следующей статье вы увидите несколько распространенных шаблонов для работы с делегатами на практике.