Nó là Func<>
gì và nó được sử dụng để làm gì?
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
Nó là Func<>
gì và nó được sử dụng để làm gì?
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
Câu trả lời:
Func<T>
là một kiểu đại biểu được xác định trước cho một phương thức trả về một số giá trị của kiểu T
.
Nói cách khác, bạn có thể sử dụng kiểu này để tham chiếu một phương thức trả về một số giá trị của T
. Ví dụ
public static string GetMessage() { return "Hello world"; }
có thể được tham chiếu như thế này
Func<string> f = GetMessage;
Func<T>
là delegate TResult Func<out TResult>()
. Không có đối số. Func<T1, T2>
sẽ là một hàm nhận một đối số.
static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)
Extension
thuộc tính chỉ được đọc bởi trình biên dịch C # / VB.Net, không phải CLR. Về cơ bản, các phương thức thể hiện (không giống như các hàm tĩnh) có tham số "this" thứ 0 ẩn. Vì vậy, phương thức thể hiện 1 đối số rất giống với hàm tĩnh 2 đối số. Sau đó, chúng ta có các đại biểu lưu trữ đối tượng đích và con trỏ hàm . Các đại biểu có thể lưu trữ đối số đầu tiên trong target hoặc không làm điều đó.
Hãy coi nó như một trình giữ chỗ. Nó có thể khá hữu ích khi bạn có mã tuân theo một mẫu nhất định nhưng không cần ràng buộc với bất kỳ chức năng cụ thể nào.
Ví dụ, hãy xem xét Enumerable.Select
phương pháp mở rộng.
Phương pháp này Func<T, TResult>
thay vì bất kỳ hàm cụ thể nào. Điều này cho phép nó được sử dụng trong bất kỳ ngữ cảnh nào mà mẫu trên được áp dụng.
Vì vậy, ví dụ, giả sử tôi có List<Person>
và tôi chỉ muốn tên của mỗi người trong danh sách. Tôi có thể làm điều này:
var names = people.Select(p => p.Name);
Hoặc nói rằng tôi muốn tuổi của mỗi người:
var ages = people.Select(p => p.Age);
Ngay lập tức, bạn có thể thấy cách tôi có thể tận dụng cùng một đoạn mã đại diện cho một mẫu (với Select
) với hai chức năng ( và ) khác nhau .p => p.Name
p => p.Age
Cách thay thế sẽ là viết một phiên bản khác Select
mỗi khi bạn muốn quét một chuỗi để tìm một loại giá trị khác. Vì vậy, để đạt được hiệu quả tương tự như trên, tôi sẽ cần:
// 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);
Với một ủy nhiệm đóng vai trò là trình giữ chỗ, tôi không cần phải viết đi viết lại cùng một mẫu trong những trường hợp như thế này.
Func<T1, T2, ..., Tn, Tr>
đại diện cho một hàm, nhận (T1, T2, ..., Tn) đối số và trả về Tr.
Ví dụ: nếu bạn có một hàm:
double sqr(double x) { return x * x; }
Bạn có thể lưu nó dưới dạng một số loại biến hàm:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
Và sau đó sử dụng chính xác như bạn sẽ sử dụng sqr:
f1(2);
Console.WriteLine(f2(f1(4)));
Vân vân.
Tuy nhiên, hãy nhớ rằng đó là một đại biểu, để biết thêm thông tin nâng cao, hãy tham khảo tài liệu.
Tôi thấy Func<T>
rất hữu ích khi tôi tạo một thành phần cần được cá nhân hóa "một cách nhanh chóng".
Lấy ví dụ rất đơn giản này: một PrintListToConsole<T>
thành phần.
Một đối tượng rất đơn giản in danh sách các đối tượng này vào bảng điều khiển. Bạn muốn cho phép nhà phát triển sử dụng nó cá nhân hóa đầu ra.
Ví dụ: bạn muốn để anh ta xác định một loại định dạng số cụ thể, v.v.
Không có chức năng
Đầu tiên, bạn phải tạo giao diện cho một lớp nhận đầu vào và tạo chuỗi để in ra bảng điều khiển.
interface PrintListConsoleRender<T> {
String Render(T input);
}
Sau đó, bạn phải tạo lớp PrintListToConsole<T>
lấy giao diện đã tạo trước đó và sử dụng nó trên từng phần tử của danh sách.
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));
}
}
}
Nhà phát triển cần sử dụng thành phần của bạn phải:
triển khai giao diện
vượt qua lớp học thực sự cho 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();
}
}
Sử dụng Func đơn giản hơn nhiều
Bên trong thành phần bạn định nghĩa một tham số có kiểu Func<T,String>
đó đại diện cho một giao diện của một hàm mà phải mất một tham số đầu vào của loại T và trả về một chuỗi (đầu ra cho giao diện điều khiển)
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));
}
}
}
Khi nhà phát triển sử dụng thành phần của bạn, anh ta chỉ cần chuyển cho thành phần việc triển khai Func<T, String>
kiểu, đó là một hàm tạo đầu ra cho bảng điều khiển.
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>
cho phép bạn xác định một giao diện phương pháp chung một cách nhanh chóng.
Bạn xác định loại đầu vào là gì và loại đầu ra là gì. Đơn giản và ngắn gọn.
Func<T1,R>
và người kia được xác định trước chung Func
các đại biểu ( Func<T1,T2,R>
, Func<T1,T2,T3,R>
và những người khác) là đại biểu chung chung mà trả về kiểu của tham số chung cuối cùng.
Nếu bạn có một hàm cần trả về các kiểu khác nhau, tùy thuộc vào các tham số, bạn có thể sử dụng một Func
ủy nhiệm, chỉ định kiểu trả về.
Nó chỉ là một đại biểu chung được xác định trước. Sử dụng nó, bạn không cần phải khai báo mọi đại biểu. Có một đại biểu được xác định trước khác, Action<T, T2...>
cũng giống như vậy nhưng trả về giá trị vô hiệu.
Có lẽ vẫn chưa muộn để thêm một số thông tin.
Tổng:
Func là một đại biểu tùy chỉnh được xác định trong không gian tên Hệ thống cho phép bạn trỏ đến một phương thức có cùng chữ ký (như các đại biểu), sử dụng 0 đến 16 tham số đầu vào và điều đó phải trả về một cái gì đó.
Danh pháp & cách sử dụng:
Func<input_1, input_2, ..., input1_6, output> funcDelegate = someMethod;
Định nghĩa:
public delegate TResult Func<in T, out TResult>(T arg);
Nơi nó được sử dụng:
Nó được sử dụng trong các biểu thức lambda và các phương thức ẩn danh.