Bottom Line: Resharper đã điều tra kiểu của bạn, và phát hiện ra rằng TFrom
có thể được sử dụng contravariantly, và TTo
covariantly. Việc chấp nhận trình tái cấu trúc sẽ cho phép bạn sử dụng các loại này với tính linh hoạt cao hơn, như được mô tả bên dưới. Nếu điều đó có thể có giá trị đối với bạn, hãy chấp nhận nó.
Lưu ý, tuy nhiên, việc chấp nhận trình tinh chỉnh này sẽ các hạn chế về cách bạn sử dụng các loại này trong tương lai. Nếu bạn đã từng viết một phương thức có tham số TTo
, bạn sẽ gặp phải lỗi trình biên dịch vì các loại biến thể không thể đọc được. Và ditto cho TFrom
: bạn sẽ không bao giờ có phương thức trả về kiểu này hoặc có thông số out
thuộc loại này.
Đó là nói với bạn rằng TFrom
là contravariant, và TTo
đó là hiệp biến. Đây là những tính năng thời gian gần đây added to C#
Loại hiệp phương sai có nghĩa là một hơn loại cụ thể có thể được thông qua tại, trong khi contravariance có nghĩa là một ít loại cụ thể có thể được thông qua trong.
IEnumerable<T>
là một ví dụ tốt về loại hiệp phương sai. Kể từ khi các mục trong một IEnumerable<T>
được chỉ đọc, bạn có thể đặt nó vào một cái gì đó cụ thể hơn:
IEnumerable<object> objects = new List<string>();
Hãy xem xét những gì có thể xảy ra nếu (theo giả thiết), bạn được phép làm việc này cho các bộ sưu tập đã được đọc/ghi :
List<object> objects = new List<string>();
objects.Add(new Car());
//runtime exception
Để có kiểu hiệp biến, một tham số chung phải được sử dụng trong một chỉ đọc cách nghiêm ; nó chỉ được viết ra khỏi từ loại này và không bao giờ đọc trong (do đó từ khóa). Đó là lý do tại sao ví dụ IEnumerable<T>
hoạt động, nhưng ví dụ List<T>
thì không. Nhân tiện, mảng do hỗ trợ phương sai hiệp phương sai (kể từ khi Java thực hiện, tôi tin), và vì vậy cùng loại lỗi thời gian chạy này có thể xảy ra với mảng.
Loại contravariance có nghĩa là ngược lại.Để hỗ trợ loại đối nghịch, thông số chung phải được đọc chỉ trong và không bao giờ viết ra. Điều này cho phép bạn thay thế các loại ít cụ thể hơn trong
Action<T>
là một ví dụ về loại contravaince:.
Action<object> objAction = (o => Console.WriteLine(o.ToString()));
Action<string> strAction = objAction;
strAction("Hello");
strAction
được khai báo để có một tham số chuỗi, nhưng nó hoạt động tốt nếu bạn thay thế một loại đối tượng. Một chuỗi sẽ được truyền vào, nhưng nếu đại biểu nó được thiết lập để làm việc với chọn để coi nó như là một đối tượng, thì cũng vậy. Không có hại gì.
Để hoàn thành, Func<T>
là trường hợp ngược của Action<T>
; đây T
chỉ trở lại, do đó nó là hiệp biến:
Func<string> strDelegate = () => "Hello";
Func<object> myObjFunc = strDelegate;
object O = myObjFunc();
myObjectFunc
được mã hoá để trả về một đối tượng. Nếu bạn đặt nó thành một cái gì đó trả về một chuỗi, sau đó, một lần nữa, không có hại gì được thực hiện.
cảm ơn bạn, nó thực sự hữu ích. – mhttk
@mhttk - tuyệt vời. Rất vui được giúp đỡ –
Có lẽ lời giải thích tốt nhất về đồng/contravariance tôi đã đọc - cảm ơn! –