Có hai điều bạn cần biết để hiểu hành vi này.
- Tất cả các đại biểu xuất phát từ
System.Delegate
, nhưng các đại biểu khác nhau có các loại khác nhau và do đó không thể được chỉ định cho nhau.
- Ngôn ngữ C # cung cấp xử lý đặc biệt để gán phương thức hoặc lambda cho đại biểu .
Bởi vì các đại biểu khác nhau có các loại khác nhau, điều đó có nghĩa là bạn không thể chỉ định một đại biểu loại này cho loại khác.
Ví dụ: đã cho:
delegate void test1(int i);
delegate void test2(int i);
Sau đó:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
Dòng đầu tiên ở trên biên dịch OK vì nó đang sử dụng cách xử lý đặc biệt để gán lambda hoặc phương thức cho một đại biểu.
Trong thực tế, dòng này được viết lại một cách hiệu quả như thế này bởi trình biên dịch:
test1 a = new test1(Console.WriteLine);
Dòng thứ hai ở trên không biên dịch vì nó đang cố gán một thể hiện của một loại cho một loại không tương thích khác.
Theo như các loại, không có sự phân công tương thích giữa test1
và test2
bởi vì chúng là các loại khác nhau.
Nếu nó giúp suy nghĩ về nó, hãy xem xét hệ thống phân cấp lớp này:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
Đoạn mã sau sẽ KHÔNG biên dịch, mặc dù Test1
và Test2
xuất phát từ cùng một lớp cơ sở:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
Điều này giải thích tại sao bạn không thể chỉ định một loại đại biểu cho loại khác. Đó chỉ là ngôn ngữ C # bình thường.
Tuy nhiên, điều quan trọng là phải hiểu lý do tại sao bạn được phép gán một phương thức hoặc lambda cho một đại biểu tương thích. Như đã lưu ý ở trên, đây là một phần hỗ trợ ngôn ngữ C # cho các đại biểu.
Vì vậy, cuối cùng để trả lời câu hỏi của bạn:
Khi bạn sử dụng, Invoke()
bạn đang chỉ định một cuộc gọi METHOD cho đại biểu bằng cách xử lý ngôn ngữ C # đặc biệt để gán các phương thức hoặc lambdas cho một đại biểu thay vì cố gắng gán một loại không tương thích - do đó nó sẽ biên dịch OK.
Để hoàn toàn rõ ràng, mã sẽ biên dịch trong OP của bạn:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Được thực sự chuyển đổi khái niệm thành một cái gì đó như:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Trong khi đó mã lỗi đang cố gán giữa hai loại không tương thích:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}