2009-05-14 28 views
5

Xem bốn dòng trong Go() phương pháp dưới đây:Sự khác biệt giữa tạo đại biểu tiềm ẩn và rõ ràng (có và không có generics)

delegate void Action<T>(T arg); 
delegate void Action(); 

void DoSomething<T>(Action<T> action) 
{ 
    //... 
} 

void DoSomething(Action action) 
{ 
    //... 
} 

void MyAction<T>(T arg) 
{ 
    //... 
} 

void MyAction() 
{ 
    //... 
} 

void Go<T>() 
{ 
    DoSomething<T>(MyAction<T>); // throws compiler error - why? 
    DoSomething(new Action<T>(MyAction<T>)); // no problems here 
    DoSomething(MyAction); // what's the difference between this... 
    DoSomething(new Action(MyAction)); // ... and this? 
} 

Lưu ý rằng lỗi biên dịch được tạo ra bởi các cuộc gọi đầu tiên là: Các đối số kiểu cho phương thức 'Hành động (T)' không thể suy ra từ việc sử dụng. Hãy thử xác định các đối số kiểu một cách rõ ràng.

+0

Tôi không thể hiểu làm thế nào điều này sẽ biên dịch (trong sự cô lập): trống DoSomething (Action hành động) {// ... } Kể từ khi T không được công bố ... là toàn bộ điều bên trong một lớp học chung chung? –

+0

Vâng tôi đang sửa đổi ví dụ của tôi bây giờ. Nên đọc Go () {... –

+0

Có phải tôi, nhưng khi tôi biên dịch mã bạn có ở đây nó biên dịch không có lỗi.Giả sử tôi đặt mã trong lớp không chung chung. Tôi đang sử dụng C# 3.5 SP1 – JoshBerke

Trả lời

13

Không có sự khác biệt giữa MyActionnew Action(MyAction) (khi cả hai đều hợp lệ) khác với tên cũ sẽ không hoạt động trong C# 1. Đây là implicit method group conversion. Có những lúc điều này không thể áp dụng, đáng chú ý nhất khi trình biên dịch không thể tìm ra loại đại biểu bạn muốn, ví dụ:

Delegate foo = new Action(MyAction); // Fine 
Delegate bar = MyAction; // Nope, can't tell target type 

Điều này xảy ra trong câu hỏi của bạn vì cả hai phương pháp liên quan đều bị quá tải. Điều này dẫn đến đau đầu, về cơ bản.

Đối với mặt generics - điều đó thật thú vị. Các nhóm phương pháp không nhận được nhiều tình cảm từ suy luận kiểu C# 3 - Tôi không chắc liệu điều đó có được cải thiện trong C# 4 hay không. Nếu bạn gọi một phương thức chung và chỉ định đối số kiểu, suy luận kiểu hoạt động khá tốt - nhưng nếu bạn cố gắng để làm điều đó theo chiều ngược lại, nó không thành công:

using System; 

class Test 
{ 
    static void Main() 
    { 
     // Valid - it infers Foo<int> 
     DoSomething<int>(Foo); 
     // Valid - both are specified 
     DoSomething<int>(Foo<int>); 
     // Invalid - type inference fails 
     DoSomething(Foo<int>); 
     // Invalid - mismatched types, basically 
     DoSomething<int>(Foo<string>); 
    } 

    static void Foo<T>(T input) 
    { 
    } 

    static void DoSomething<T>(Action<T> action) 
    { 
     Console.WriteLine(typeof(T)); 
    } 
} 

Loại suy luận trong C# 3 là rất phức tạp, và hoạt động tốt trong hầu hết các trường hợp (đặc biệt là rất tốt cho LINQ) nhưng không thành công trong một vài trường hợp khác. Trong một thế giới lý tưởng, sẽ dễ hiểu hơn để hiểu được mạnh mẽ hơn trong các phiên bản sau ... chúng ta sẽ thấy!

+0

Chúc mừng! Tôi chấp nhận câu trả lời khác nhưng câu trả lời của bạn vẫn hữu ích. +1 –

3

phi-generic tạo đại biểu ngầm chỉ là cú pháp đường, vì vậy trình biên dịch tạo ra chính xác cùng mã cho

DoSomething(MyAction); 

DoSomething(new Action(MyAction)); 

vì nó có thể suy ra các loại của các đại biểu trực tiếp từ đối số phương thức & ngữ cảnh.

Với đại biểu chung, bạn phải chỉ định loại đại biểu do hiệp phương sai và đối nghịch (xem http://msdn.microsoft.com/en-us/library/ms173174(VS.80).aspx để biết chi tiết) - T trong hành động có thể là siêu kiểu cho T trong phương thức và vẫn sẽ được chấp nhận một phương thức đại biểu. Vì vậy, bạn cần phải xác định T trong delegate một cách rõ ràng vì trình biên dịch không thể tự tìm ra nó.

+0

Chúc mừng, giờ tôi đã hiểu. Liên kết đến hiệp phương sai so với bài viết đối nghịch cho những người không hiểu: http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) –

+0

Tôi muốn nói nhiều hơn về những hạn chế của suy luận kiểu so với co/contravariance, cá nhân. Nếu bạn đọc phần spec về suy luận kiểu (tôi không thể nhớ nó ngay bây giờ), bạn sẽ thấy rằng các nhóm phương pháp về cơ bản không nhận được nhiều cơ hội. –

1

Chỉ cần một sidenote .. Vì một số lý do này hoạt động trong VB.

Dường như việc triển khai bộ tiền xử lý trong C# và VB khác nhau khi tôi chuyển sang nhóm Methodgroup/adderessof thành một đại biểu.

Các vấn đề liên quan