Chắc chắn lý do thực tế cho việc sử dụng Func
thay vì một đại biểu cụ thể là C # coi các đại biểu được tuyên bố riêng là các loại hoàn toàn khác nhau.
Mặc dù Func<int, bool>
và Predicate<int>
cả hai đều có kiểu đối số và trả về giống hệt nhau, chúng không tương thích với gán. Vì vậy, nếu mỗi thư viện khai báo loại đại biểu riêng cho từng mẫu đại biểu, các thư viện đó sẽ không thể tương tác trừ khi người dùng chèn các đại biểu "bắc cầu" để thực hiện chuyển đổi.
// declare two delegate types, completely identical but different names:
public delegate void ExceptionHandler1(Exception x);
public delegate void ExceptionHandler2(Exception x);
// a method that is compatible with either of them:
public static void MyExceptionHandler(Exception x)
{
Console.WriteLine(x.Message);
}
static void Main(string[] args)
{
// can assign any method having the right pattern
ExceptionHandler1 x1 = MyExceptionHandler;
// and yet cannot assign a delegate with identical declaration!
ExceptionHandler2 x2 = x1; // error at compile time
}
Bằng cách khuyến khích mọi người sử dụng Func, Microsoft hy vọng rằng điều này sẽ làm giảm bớt vấn đề của các loại đại biểu không tương thích. Các đại biểu của mọi người sẽ chơi tốt với nhau, bởi vì họ sẽ được kết hợp dựa trên các loại tham số / trả về của họ.
Nó không giải quyết được tất cả các vấn đề, bởi vì Func
(và Action
) không thể có out
hoặc ref
tham số, nhưng những thứ đó ít được sử dụng hơn.
Cập nhật: trong các bình luận Svish nói:
Tuy nhiên, việc chuyển đổi một loại tham số từ Func sang Vị ngữ và quay lại, dường như không có sự khác biệt nào? Ít nhất nó vẫn biên dịch mà không có bất kỳ vấn đề.
Có, miễn là chương trình của bạn chỉ gán các phương thức cho các đại biểu, như trong dòng đầu tiên của Main
hàm của tôi . Trình biên dịch âm thầm tạo mã cho một đối tượng ủy nhiệm mới chuyển tiếp đến phương thức. Vì vậy, trong Main
chức năng của mình , tôi có thể thay đổi x1
thành loại ExceptionHandler2
mà không gây ra vấn đề gì.
Tuy nhiên, trên dòng thứ hai tôi cố gắng chỉ định đại biểu đầu tiên cho một đại biểu khác. Thậm chí còn nghĩ rằng loại đại biểu thứ 2 có chính xác cùng loại tham số và kiểu trả về, trình biên dịch đưa ra lỗi CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.
Có lẽ điều này sẽ làm cho nó rõ ràng hơn:
public static bool IsNegative(int x)
{
return x < 0;
}
static void Main(string[] args)
{
Predicate<int> p = IsNegative;
Func<int, bool> f = IsNegative;
p = f; // Not allowed
}
Phương pháp của tôi IsNegative
là một điều hoàn toàn tốt để gán cho p
và f
các biến, miễn là tôi làm như vậy trực tiếp. Nhưng sau đó tôi không thể gán một trong các biến đó cho biến kia.