select * from yourtable
group by id
having rev=max(rev);
Func<T>
является предопределенным типом делегата для метода, который возвращает некоторое значение типа T
.
Другими словами, вы можете использовать этот тип для ссылки на метод, который возвращает некоторое значение T
. Например,
public static string GetMessage() { return "Hello world"; }
можно ссылаться так, как это
Func<string> f = GetMessage;
Подумайте об этом как заполнитель. Это может быть весьма полезно, если у вас есть код, который следует за определенным шаблоном, но не должен быть привязан к какой-либо конкретной функции.
Например, рассмотрите метод расширения Enumerable.Select
.
Этот метод принимает вместо Func<T, TResult>
любую конкретную функцию. Это позволяет использовать его в в любом контексте , где применяется вышеприведенный шаблон.
Так, например, скажем, у меня есть List<Person>
, и я хочу просто имя каждого человека в список. Я могу это сделать:
var names = people.Select(p => p.Name);
Или сказать, что я хочу возраст каждого человека:
var ages = people.Select(p => p.Age);
Сразу видно, как я был способен использовать тот же код, представляющий шаблон (с Select
) с двумя различными функциями (p => p.Name
и p => p.Age
) .
Альтернативой было бы написать другую версию Select
каждый раз, когда вы хотели бы сканировать последовательность для другого значения. Поэтому для достижения такого же эффекта, как и выше, мне понадобится:
// Presumably, the code inside these two methods would look almost identical;
// the only difference would be the part that actually selects a value
// based on a Person.
var names = GetPersonNames(people);
var ages = GetPersonAges(people);
Когда делегат выступает в качестве заполнителя, я освобождаюсь от необходимости повторять одну и ту же модель снова и снова в таких случаях.
Func<T1, T2, ..., Tn, Tr>
представляет собой функцию, которая принимает (T1, T2, ..., Tn) аргументы и возвращает Tr.
Например, если у вас есть функция:
double sqr(double x) { return x * x; }
Вы можете сохранить его как какую-то функцию-переменную:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
И затем используйте точно так же, как вы бы использовали sqr:
f1(2);
Console.WriteLine(f2(f1(4)));
и т. д.
Помните, что это делегат, поскольку более подробная информация относится к документации.
Я нахожу Func<T>
очень полезным, когда создаю компонент, который нужно персонализировать «на лету».
Возьмем этот очень простой пример: компонент PrintListToConsole<T>
.
Очень простой объект, который печатает этот список объектов на консоли. Вы хотите, чтобы разработчик, который использует его, персонализировал вывод.
Например, вы хотите дать ему определение определенного типа номера и т. Д.
Без Func
g7]Во-первых, вам нужно создать интерфейс для класса, который берет ввод и выводит строку для печати на консоль.
interface PrintListConsoleRender<T> {
String Render(T input);
}
Затем вам нужно создать класс PrintListToConsole<T>
который принимает ранее созданный интерфейс и использует его по каждому элементу списка.
class PrintListToConsole<T> {
private PrintListConsoleRender<T> _renderer;
public void SetRenderer(PrintListConsoleRender<T> r) {
// this is the point where I can personalize the render mechanism
_renderer = r;
}
public void PrintToConsole(List<T> list) {
foreach (var item in list) {
Console.Write(_renderer.Render(item));
}
}
}
Разработчик, которому необходимо использовать ваш компонент, должен:
PrintListToConsole
class MyRenderer : PrintListConsoleRender<int> {
public String Render(int input) {
return "Number: " + input;
}
}
class Program {
static void Main(string[] args) {
var list = new List<int> { 1, 2, 3 };
var printer = new PrintListToConsole<int>();
printer.SetRenderer(new MyRenderer());
printer.PrintToConsole(list);
string result = Console.ReadLine();
}
}
. Использование Func намного проще
. Внутри компонента вы определяете параметр type Func<T,String>
, который представляет собой интерфейс функции, которая принимает входной параметр типа T и возвращает строку (вывод для консоли)
class PrintListToConsole<T> {
private Func<T, String> _renderFunc;
public void SetRenderFunc(Func<T, String> r) {
// this is the point where I can set the render mechanism
_renderFunc = r;
}
public void Print(List<T> list) {
foreach (var item in list) {
Console.Write(_renderFunc(item));
}
}
}
Когда разработчик использует ваш компонент, он просто переходит к компонент реализует тип Func<T, String>
, то есть функционал на котором создается вывод для консоли.
class Program {
static void Main(string[] args) {
var list = new Array[1, 2, 3];
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
printer.Print();
string result = Console.ReadLine();
}
}
Func<T>
позволяет вам определять общий интерфейс метода «на лету». Вы определяете тип ввода и тип вывода. Простой и лаконичный.
Func<T1,R>
и другие предопределенные общие Func
делегаты (Func<T1,T2,R>
, Func<T1,T2,T3,R>
и другие) являются универсальными делегатами, которые возвращают тип последнего общего параметра.
Если у вас есть функция, которая должна возвращать разные типы, в зависимости от параметров, вы можете использовать делегат Func
, указав тип возврата.
Это только предопределенный общий делегат. Используя его, вам не нужно объявлять каждого делегата. Существует еще один предопределенный делегат, Action<T, T2...>
, который является тем же, но возвращает void.