Я нахожу Func<T>
очень полезным, когда я создаю компонент, который нужно персонализировать "на лету".
Возьмите этот очень простой пример: компонент PrintListToConsole<T>
.
Очень простой объект, который выводит этот список объектов на консоль.Вы хотите позволить разработчику, использующему его, персонализировать вывод.
Например, вы хотите, чтобы он определил определенный тип числового формата и т. Д.
Без функции
Сначала вы должны создать интерфейс для класса, который принимает входные данные и создает строку для печати на консоль.
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 намного проще
Внутри компонента вы определяете параметр типа 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 List<int> { 1, 2, 3 }; // should be a list as the method signature expects
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
printer.Print(list);
string result = Console.ReadLine();
}
}
Func<T>
позволяет определить общий интерфейс методана лету. Вы определяете, какой тип ввода и какой тип выхода.Просто и кратко.