Различие между двумя основными типами делегатов в C # — Func и Action - может привести к путанице из-за их схожего синтаксиса и родительского типа. Хотя оба типа делегатов могут получать функции со стрелками или значения группы методов, разница заключается в том, что они должны возвращать (или не ожидается). Ожидается, что методы Func будут возвращать значение, в то время как методы Action, как ожидается, будут недействительными.
В этой статье мы рассмотрим различия между двумя типами делегатов, а также соответствующие варианты использования.
Чтобы разобраться в двух типах, нам нужно сначала понять, что такое делегат и как его предполагается использовать.
Что такое делегаты в C#
Делегаты (проще говоря) помогают нам назначать методы переменным. Таким образом, делегат может использоваться для передачи метода в качестве параметра другим методам.
Ради ортогональности у нас иногда возникает необходимость передать метод, основанный на некоторых критериях, исполняемому методу для вызова — и вот тут-то и появляются делегаты.
Делегаты могут быть объявлены на уровне пространства имен. Они также используются для обратных вызовов. Делегату также могут быть назначены функции со стрелками или методы класса. Также поддерживается объединение обратных вызовов делегатов в цепочку при условии, что они имеют одинаковые подписи.
Объявление делегата похоже на объявление класса в C #. Возьмем это для примера.
public class DelegateExample
{
public delegate string Greet();
public DelegateExample()
{
Greet greet = this.SayHelloWorld;
greet();
}
private string SayHelloWorld()
{
return "Hello world";
}
}
Функция в C#
Последний параметр типа в Функция объявление - это тип выходного значения. Как мы знаем, функция должна возвращать значение. Итак, у нас всегда должен быть хотя бы один параметр типа.
Давайте посмотрим простой пример функции в C #.
public class FuncExampleOne
{
Func<string> Greet;
public FuncExampleOne()
{
Greet = this.GreetUserInEnglish;
Greet();
}
public string GreetUserInEnglish()
{
return "Привет! Как у тебя дела сегодня";
}
}
В приведенном выше примере у нас есть метод GreetUserInEnglish, который возвращает строку. Затем мы присваиваем ее переменной Func<string>, которую позже вызываем непосредственно перед выходом из конструктора.
Давайте рассмотрим другой пример функции, в которой используется числовой параметр и возвращается строковый вывод.
public class FuncExampleTwo
{
Func<int, string> SayTemperature;
public FuncExampleTwo()
{
SayTemperature = this.GiveTemperatureSummary;
Console.WriteLine(SayTemperature(30));
}
public string GiveTemperatureSummary(int temp)
{
return $"It's {temp} degrees outside.";
}
}
Функциональная переменная также может быть функцией со стрелкой, и мы могли бы передавать функциональную переменную в качестве параметра другим методам, как мы видим в примере ниже.
public class FuncExampleThree
{
public FuncExampleThree()
{
Func<int, string> GetFriendlyTemp = (int temp) =>
{
return $"It's {temp} degrees outside.";
};
DisplayTempText(GetFriendlyTemp);
// На улице 30 градусов.
}
public void DisplayTempText(Func<int, string> getFriendlyTemp)
{
Console.WriteLine(getFriendlyTemp());
}
}
Действие на C#
Большинство условных переменных функции также применимы к действию. Основное отличие заключается в том, что действие ничего не возвращает. Таким образом, все параметры типа любого объявления действия являются входными параметрами. В случае, когда Действие не принимает никаких параметров, параметр типа не требуется.
Например, это было бы допустимым объявлением действия в C #.
public class ActionExampleOne {
Action Greet;
public DelegateExample() {
Greet = this.SayHelloWorld;
Greet();
public void SayHelloWorld() {
Console.WriteLine("Hello world!");
}
По подписи действия мы можем сказать, что они идеально подойдут для обратных вызовов.
Еще одной особенностью, уникальной для переменных действия, является возможность их объединения в цепочку.
public class ActionChainExample
{
public ActionChainExample()
{
Action<int> GetFriendlyTemp = (int _) => { };
GetFriendlyTemp += (int temp) =>
{
Console.Write($"It's {temp} degrees outside.");
GetFriendlyTemp += (int temp) =>
{
string _season = temp < 40 ? "winter" : "summer";
Console.
GetFriendlyTemp(45);
// На улице 45 градусов. У нас сейчас летний сезон!
}
Заключительное слово
Когда приходится выбирать между обоими типами делегатов, задайте себе следующие вопросы
Что возвращает этот метод?
Возникнет ли у меня необходимость в объединении этого метода в цепочку?
Спасибо что прочитали до конца, если статья была для Вас полезной, пожалуйста подпишитесь на мой канал.