воскресенье, 9 января 2022 г.

Action , Predicate , Func

Чтобы лишь программиста C# необходимости для каждого случая создавать собственные делегаты в библиотеке классов NET.Framework определены и реализованы несколько типов. 

Самые распространенные из них - Action <T>, Predicate <T>, Func <T>. 

Символ Т в имени делегата означает его обобщенную форму, маскирует собой любой тип, переданный делегату.

источник

Action <T>

Один из самых распространённых делегатов. 

Делегат не шаблонизированный, поэтому нет возможности объявить общий вид. 

И в зависимости от количества необходимых передаваемых параметров в делегат, программист должен выбирать соответствующую форму его объявления. 

В версии NET.Framework 3.5 есть 4 версии этого делегата, начиная с версии 4.0 – их уже 16.

Action, часто используется для обратного вызова:

static void Main(string[] args)

{

Action<double, double> actiondelegate;

actiondelegate = Sum;

Operation(11.88, 6.55, actiondelegate);

actiondelegate = Substract;

Operation(100.22, 9.64, actiondelegate);

Console.Read();

}


static void Operation(double a, double b, Action<double, double> actiondelegate)

{

if (a > b)

actiondelegate(a, b);

}


static void Sum(double a, double b)

{

Console.WriteLine("Сумма чисел: " + (a + b));

}


static void Substract(double a, double b)

{

Console.WriteLine("Разность чисел: " + (a - b));

}

 

Action – void-делегат. Все версии делегата возвращают void-значение. Это серьезное ограничение, поскольку делегат не должен использоваться для информации о методах, имеющих тип возвращаемого значения отличный от void.

Но, если программист использует его для хранения ссылки на не void-метод, то ошибки не будет, просто возвращаемое значение использовать не удастся, оно будет проигнорировано средой исполнения.

Для хранения ссылок на методы с любым возвращаемым значением используются делегаты: Func <T> и Predicate<T>.


Func<T>

Также как и Action, делегат Func не шаблонизирован, в разных версиях NET.FrameWork имеет от 4 до 16 видов объявлений, которые различаются количеством параметров.


Его общее объявление: TResult Func<in T, out TResult>(T arg).


Делегат возвращает значение любого пользовательского или встроенного типа (TResult) может принимать параметры любого типа (Т): от 1 до 16.


Func применяется как делегат, передаваемый в качестве параметра другому методу: для алгоритмов расчёта, сортировки или встроенных методов:


using System;


public class FuncExample

{

public static void Main()

{

Func<string, string> MethodConvert = ConvertUserString;

string str = "Владимир";

Console.WriteLine(MethodConvert(str));

}


private static string ConvertUserString(string impStr)

{

result = impStr + DateTime.Now.Hour.ToString();


return result.ToUpper();

}

}

Predicate <T>

Встроенный, нешаблонизированый тип делегата. 

Имеет 16 версий объявления начиная с .NET Framewok4.0. 

Как и в случае Func и Action версии делегата различаются количество входных параметров. 

Выходной или возвращаемое значение всегда одно, типа bool, поэтому назначения делегата – передавать ссылку на метод, в котором реализован алгоритм сравнения объектов.

По функциональности полностью идентичен Func<T, bool>. Однако введен в библиотеку типов по двум причинам: исторической, поскольку в языке появился раньше, чем универсальные типы; и из стремления к строгому типизированную в framework, для создания специального типа для каждого круга задач.


using System;

using System.Collections.Generic;


public class Drink

{

private string title;

private int yearofbotling;


public Drink(string title, int year)

{

title = title;

yearofbotling = year;

}


public string Title 

{

get { return title; }

}


public int Yearofbotling 

{

get { return yearofbotling; }

}

}


public class Example

{

public static void Main()

{

Random rnd = new Random();

List<Drink> drinks = new List<Drink>();

drinks.AddRange( new Drink[] { 

new Drink("Московская Сивуха", 2015),

new Drink("VielleBonSecours", 2016),

new Drink("Массандра", 1999),

new Drink("Шато Лафитэ", 1905),

new Drink("Ley.925", 2006) }

);

int[] years = { 1900, 1965, 1980, 2015 };

int foundedBeforeYear = years[rnd.Next(0, years.Length)];

Console.WriteLine("Напитки разлиты ранее {0}:", foundedBeforeYear);


foreach (var dr in drinks.FindAll( delegate (int x) { x.Yearofbotling <= foundedBeforeYear };)//Используем анонимный метод.


Console.WriteLine("{0}: {1}", dr.Title, dr.Yearofbotling);

}

}

В предыдущем примере использован анонимный метод в качестве инициализации делегата Predicate<Т>, запись:


delegate (int x) { x.Yearofbotling <= foundedBeforeYear } 

неявно приводится компилятором к созданию делегата, инициализации его методом. Никто, однако, не мешает сделать метод именованным и явно передать его в делегат Predicate.

По сути весь тяжкий выбор для программиста между Predicate<T> и Func<T, bool> лежит в области семантики: в случае Predicate метод на основании инструкций вернет true или false, а в случае Func<T,bool> тип bool, а это не всегда одно и то же.

Комментариев нет:

Отправить комментарий

Паттерн 'Репозиторий' в ASP.NET

  Последнее обновление: 1.11.2015         Одним из наиболее часто используемых паттернов при работе с данными является паттерн 'Репозито...