Для того, чтобы поделиться как можно более полным решением, я собираюсь представить три различных способа работы, но теперь я собираюсь начать с самого основного принципа.
Краткое введение
Все языки CLR ( Common Language Runtime ) (такие как C # и Visual Basic) работают в виртуальной машине под названием CLI ( Common Language Interpreter ), которая выполняет код на более высоком уровне. чем родные языки, такие как C и C ++ (которые напрямую компилируются в машинный код). Из этого следует, что методы - это не какой-либо вид скомпилированного блока, а просто структурированные элементы, которые CLR распознает и использует для извлечения своего тела и передачи его встроенным инструкциям машинного кода. Таким образом, вы не можете думать о том, чтобы передать метод в качестве параметра, потому что метод сам по себе не создает никакого значения: это недопустимое выражение! Итак, вы собираетесь запутаться в концепции делегата.
Что такое делегат?
Делегат представляет указатель на метод. Поскольку (как я уже говорил выше) метод не является значением, в языках CLR существует специальный класс: Delegate
. Этот класс обертывает любой метод, и вы можете неявно приводить к нему любой метод.
Посмотрите на следующий пример использования:
static void MyMethod()
{
Console.WriteLine("I was called by the Delegate special class!");
}
static void CallAnyMethod(Delegate yourMethod)
{
yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}
static void Main()
{
CallAnyMethod(MyMethod);
}
Три способа:
Путь 1
Используйте специальный класс Delegate
напрямую, как в примере выше. Проблема этого решения заключается в том, что ваш код не будет проверяться при динамической передаче аргументов, не ограничивая их типами, указанными в объявлении метода.
Путь 2/3
Помимо специального класса Delegate
, концепция делегатов распространяется на пользовательские делегаты, которые являются объявлениями методов, которым предшествует ключевое слово delegate
, и ведут себя как обычный метод. Они так проверены, и вы получите код " perfect ".
Посмотрите на следующий пример:
delegate void PrintDelegate(string prompt);
static void PrintSomewhere(PrintDelegate print, string prompt)
{
print(prompt);
}
static void PrintOnConsole(string prompt)
{
Console.WriteLine(prompt);
}
static void PrintOnScreen(string prompt)
{
MessageBox.Show(prompt);
}
static void Main()
{
PrintSomewhere(PrintOnConsole, "Press a key to get a message");
Console.Read();
PrintSomewhere(PrintOnScreen, "Hello world");
}
Второй способ не писать свой собственный делегат - использовать один из них, объявленный в системных библиотеках:
Action
переносит void
без аргументов.
Action<T1>
заключает void
в один аргумент.
Action<T1, T2>
переносит void
с двумя аргументами.
- И так далее ...
Func<TR>
упаковывает функцию с TR
типом возврата и без аргументов.
Func<T1, TR>
упаковывает функцию с TR
возвращаемым типом и одним аргументом.
Func<T1, T2, TR>
оборачивает функцию с TR
возвращаемым типом и двумя аргументами.
- И так далее ...
(Это последнее решение, которое публикуют многие люди.)