2010-02-26 40 views
7

Tại sao tính năng này không hoạt động? Tôi không hiểu hiệp phương sai của đại biểu một cách chính xác?Delegate Hiệp phương sai lầm Confusion!

public delegate void MyDelegate(object obj) 

public class MyClass 
{ 
    public MyClass() 
    { 
     //Error: Expected method with 'void MyDelegate(object)' signature 
     _delegate = MyMethod; 
    } 

    private MyDelegate _delegate; 

    public void MyMethod(SomeObject obj) 
    {} 

} 
+4

Amiteration allpleation luôn amuses – Bob

+0

Tôi đã cố gắng trả lời các câu hỏi như vậy trong một bài đăng FAQ ngắn: http://blogs.msdn.com/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx Vẫn còn nhiều sự nhầm lẫn xung quanh tính năng này ... –

Trả lời

12

đúng - bạn không hiểu hiệp phương sai một cách chính xác - chưa :) Mã của bạn sẽ làm việc nếu bạn có các loại tương tự, nhưng như trở giá trị, như thế này:

public delegate object MyDelegate() 

public class MyClass 
{ 
    public MyClass() 
    { 
     _delegate = MyMethod; 
    } 

    private MyDelegate _delegate; 

    public SomeObject MyMethod() { return null; } 
} 

Điều đó sẽ chứng minh hiệp phương sai . Ngoài ra, bạn có thể giữ nó như là thông số nhưng chuyển các loại xung quanh:

public delegate void MyDelegate(SomeObject obj) 

public class MyClass 
{ 
    public MyClass() 
    { 
     _delegate = MyMethod; 
    } 

    private MyDelegate _delegate; 

    public void MyMethod(object obj) {} 
} 

này bây giờ chứng tỏ contravariance.

Quy tắc ngón tay cái của tôi là tự hỏi mình, "được ủy quyền, tôi có thể làm gì với nó? Nếu tôi có thể vượt qua trong một đối số sẽ phá vỡ phương pháp, việc chuyển đổi sẽ thất bại. sẽ ngắt số gọi người gọi, chuyển đổi sẽ không thành công ".

Trong code của bạn, bạn có thể gọi là:

_delegate(new object()); 

Vào thời điểm đó, người nghèo MyMethod có một tham số đó là nghĩa là loại SomeObject, nhưng là thực loại object. Điều này sẽ là một điều rất xấu, do đó trình biên dịch dừng nó xảy ra.

Tất cả điều đó có hợp lý hơn không?

+0

Điều này không giải quyết được vấn đề của mã ban đầu, nơi một đại biểu chung cần được triển khai theo cách cụ thể hơn. Đây là toàn bộ điểm của Generics trong ngôn ngữ. –

+0

Tôi đã có nó ngược và nó có ý nghĩa hơn nhiều bây giờ! Loại chung hơn phải là một tham số trên phương thức không nằm trong đại biểu. Cảm ơn! –

+0

@Payton Byrd: Điều gì khiến bạn nghĩ đó là vấn đề của mã gốc? Tôi cho rằng OP muốn biết tại sao mã của anh ta không hoạt động, vì đó là câu hỏi anh ta hỏi. –

1

Các MyDelegate loại tuyên bố rằng bạn có thể vượt qua bất kỳ loại đối tượng. Tuy nhiên, MyMethod chỉ mất đối tượng thuộc loại SomeObject. Điều gì sẽ xảy ra nếu tôi cố gắng gọi đại biểu đi qua một loại đối tượng khác: _delegate("a string object")? Theo tuyên bố của MyDelegate, điều này sẽ được cho phép, nhưng chức năng của bạn MyMethod thực sự không thể nhận được đối số chuỗi.

4

Bạn cần sử dụng chung chung.

EDIT: Tại sao? Bởi vì như một poster khác lưu ý, Object và SomeObject không tương đương với cùng một thứ như Object có thể không phải là SomeObject. Đây là toàn bộ số của Generics trong ngôn ngữ.

public delegate void MyDelegate<T>(T obj) 

public class MyClass 
{ 
    public MyClass() 
    { 
     _delegate = MyMethod; 
    } 

    private MyDelegate<SomeObject> _delegate; 

    public void MyMethod(SomeObject obj) 
    { 
    } 
} 
+0

Bạn đúng, đây là ý định ban đầu của tôi với mã! Tôi nhìn vào những gì 4.0 cung cấp và họ sẽ cho phép đối với một số công cụ đại biểu chung khá mát mẻ: http://blog.tlk.com/dot-net/2009/c-sharp-4-covariance-and-contravariance –

+1

@Adam: Bạn nên lưu ý rằng phương sai bạn đã xem trong bài đăng của bạn không phải là mới đối với C# 4.0 - nó có sẵn trong C# 2.0. Nó chỉ là * chung * phương sai mới trong C# 4. –

4

Đối số có thể thay đổi, kiểu trả về có thể thay đổi. Nếu đại biểu được gọi với số object không phải là trường hợp của SomeObject, bạn sẽ gặp phải lỗi nhập. Mặt khác, trả lại SomeObject từ một thường lệ được gói trong một đại biểu trả về object là tốt.

1

Từ liên kết MSDN mà bạn cung cấp

Hiệp phương sai cho phép một phương pháp để có một có nguồn gốc nhiều trở lại loại hơn là những gì quy định tại các đại biểu. Contravariance cho phép một phương thức với các loại tham số ít bắt nguồn hơn so với loại đại biểu.

Bạn đang cố gắng sử dụng một nguồn gốc hơn tham số kiểu mà không được hỗ trợ (mặc dù .NET 4.0 có thể sẽ vì đây đã được sắp xếp ra nhiều vấn đề hiệp phương sai/contravariance).

+0

ngày 12 tháng 4 phải không? Chẳng bao lâu nữa, chẳng bao lâu nữa ... –

+1

Không, mã này cũng không hoạt động trong C# 4.0. Nếu không, bạn sẽ có thể truyền "đối tượng" cho một phương thức cần "SomeObject", không an toàn. –

0

Hiệp phương sai và Đối nghịch là về việc hiểu Nguyên tắc là thừa kế.

Trong cả hai hiệp phương sai và hiệp phương sai, s.th. được "truyền theo", hoặc là giá trị trả về hoặc làm đối số cho phương thức ủy nhiệm. Đó là "thông qua cùng" đã được "bắt" trong một receptacle. Trong C# - hoặc thuật ngữ lập trình như vậy - chúng ta sử dụng từ từ cho cái mà tôi gọi là receptacle. Đôi khi bạn phải quay trở lại các từ khác để nắm bắt được ý nghĩa của các từ thuật ngữ thường được sử dụng.

Dù sao, nếu bạn hiểu được thừa kế, mà rất có khả năng bất kỳ người đọc nào ở đây sẽ, thì điều duy nhất cần chú ý là nơi chứa, i. e. xô được sử dụng để đánh bắt phải có cùng loại hoặc loại có nguồn gốc ít hơn loại được truyền - điều này đúng với cả hiệp phương sai và đối xứng.

Thừa kế nói rằng bạn có thể bắt chim trong một thùng động vật vì chim là một con vật. Vì vậy, nếu một tham số của một phương pháp có để bắt một con chim bạn có thể bắt nó trong một xô động vật (một tham số của loại động vật), mà sau đó là contravariance. Và nếu phương pháp của bạn, nghĩa là đại biểu của bạn trả về một con chim, thì "xô" cũng có thể là một loại chim hoặc ít có nguồn gốc (của một loại cha) có nghĩa là biến mà bạn bắt được giá trị trả về của phương thức phải là cùng một loại hoặc ít có nguồn gốc hơn giá trị trả lại.

Chỉ cần chuyển đổi suy nghĩ của bạn để phân biệt đối xử giữa cái đang được truyền đi và cái bắt được như sau đó tất cả sự phức tạp về hiệp phương sai và contravariance hòa tan độc đáo. Sau đó, bạn nhận ra rằng nguyên tắc tương tự là tại nơi làm việc. Nó chỉ là thừa kế không thể bị vi phạm vì nó chỉ chảy một chiều.

Và trình biên dịch rất thông minh khi bạn đúc thùng theo kiểu chuyên biệt hơn (một lần nữa, và khi cần) thì chỉ sau đó bạn sẽ có được tất cả các phương thức chuyên biệt được thêm vào lớp dẫn xuất. Đó là vẻ đẹp của nó. Vì vậy, nó là bắt, đúc và sử dụng những gì bạn có và có lẽ cần.

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