Sự khác biệt giữa <out T>
và là <T>
gì? Ví dụ:
public interface IExample<out T>
{
...
}
so với
public interface IExample<T>
{
...
}
Sự khác biệt giữa <out T>
và là <T>
gì? Ví dụ:
public interface IExample<out T>
{
...
}
so với
public interface IExample<T>
{
...
}
Câu trả lời:
Các out
từ khóa trong Generics được sử dụng để biểu thị rằng các loại T trong giao diện là hiệp biến. Xem hiệp phương sai và chống chỉ định để biết chi tiết.
Ví dụ kinh điển là IEnumerable<out T>
. Vì IEnumerable<out T>
là covariant, bạn được phép làm như sau:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Dòng thứ hai ở trên sẽ thất bại nếu điều này không đồng biến, mặc dù về mặt logic nó sẽ hoạt động, vì chuỗi xuất phát từ đối tượng. Trước khi phương sai trong các giao diện chung được thêm vào C # và VB.NET (trong .NET 4 với VS 2010), đây là lỗi thời gian biên dịch.
Sau .NET 4, IEnumerable<T>
được đánh dấu covariant và trở thành IEnumerable<out T>
. Vì IEnumerable<out T>
chỉ sử dụng các phần tử bên trong nó và không bao giờ thêm / thay đổi chúng, nên nó an toàn để coi một bộ sưu tập chuỗi vô số như một bộ sưu tập các đối tượng, có nghĩa là nó là đồng biến .
Điều này sẽ không hoạt động với một loại như IList<T>
, vì IList<T>
có một Add
phương pháp. Giả sử điều này sẽ được cho phép:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
Sau đó bạn có thể gọi:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
Tất nhiên, điều này sẽ thất bại - vì vậy IList<T>
không thể đánh dấu covariant.
Ngoài ra còn có, btw, một tùy chọn cho in
- được sử dụng bởi những thứ như giao diện so sánh. IComparer<in T>
, ví dụ, hoạt động theo cách ngược lại. Bạn có thể sử dụng một bê tông IComparer<Foo>
trực tiếp như một IComparer<Bar>
nếu Bar
là một lớp con của Foo
, bởi vì IComparer<in T>
giao diện là contravariant .
Image
là một lớp trừu tượng;) Bạn có thể làm new List<object>() { Image.FromFile("test.jpg") };
mà không có vấn đề gì, hoặc bạn cũng có thể làm new List<object>() { new Bitmap("test.jpg") };
như vậy. Vấn đề với bạn là điều đó new Image()
không được phép (bạn cũng không thể làm var img = new Image();
được)
IList<object>
là một ví dụ kỳ quái, nếu bạn muốn object
bạn không cần thuốc generic.
Để dễ dàng ghi nhớ việc sử dụng in
và out
từ khóa (cũng là hiệp phương sai và chống đối), chúng ta có thể hình ảnh kế thừa như gói:
String : Object
Bar : Foo
xem xét,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
và các chức năng,
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
Hàm chấp nhận ICovariantSkinned<Fruit>
sẽ có thể chấp nhận ICovariantSkinned<Fruit>
hoặc ICovariantSkinned<Bananna>
vì ICovariantSkinned<T>
là giao diện covariant và Banana
là một loại Fruit
,
chức năng chấp nhận ISkinned<Fruit>
sẽ chỉ có thể chấp nhận ISkinned<Fruit>
.
" out T
" có nghĩa là loại đó T
là "covariant". Điều đó hạn chế T
chỉ xuất hiện dưới dạng giá trị trả về (bên ngoài) trong các phương thức của lớp, giao diện hoặc phương thức chung. Hàm ý là bạn có thể truyền kiểu / giao diện / phương thức tương đương với siêu kiểu T
.
Ví dụ ICovariant<out Dog>
có thể được đúc ICovariant<Animal>
.
out
thực thi chỉ T
có thể được trả lại, cho đến khi tôi đọc câu trả lời này. Toàn bộ khái niệm có ý nghĩa hơn bây giờ!
Từ liên kết bạn đã đăng ....
Đối với các tham số loại chung, từ khóa out chỉ định rằng tham số loại là covariant .
EDIT : Một lần nữa, từ liên kết bạn đã đăng
Để biết thêm thông tin, hãy xem Hiệp phương sai và Chống chỉ định (C # và Visual Basic). http://msdn.microsoft.com/en-us/l Library / ee207183.aspx