问题描述
这是我的原帖:C#泛型继承和协方差
仅在我的只读接口上,我希望继承工作.
public delegate Boolean EnumerateItemsDelegate(ItemType item);公共接口 IReadOnlyCollection{Boolean containsItem(ItemType item);数组复制到数组();void EnumerateItems(EnumerateItemsDelegate enumerateDelegate);UInt32 计数 { 得到;}UInt32容量{得到;}}
像这样,除了编译的地方:-p
这就是我想要的工作:
IReadOnlyCollections;IReadOnlyCollectiono = s;
这个问题好像没有什么问题,所以我会补几个问题来回答.
什么是协变转换?
假设我们有一些类型 Fruit
和 Apple
和 Banana
具有明显的关系;Apple
是一种Fruit
,等等.
协变转换是一种类型参数的可转换性意味着泛型类型的可转换性.如果 Apple
可转换为 Fruit
,并且 Bowl
可转换为 Bowl
,则 Bowl
在 T 中是协变的.
什么是逆变转换?
逆变转换是一种协变转换,它反转方向而不是保持方向.如果 Eater
可转换为 Eater
,则 Eater
在 T 中是逆变的.
如何在其类型参数中将接口或委托标记为协变或逆变?
协变类型参数标记为out
,逆变类型参数标记为in
.
这是为了助记:协变接口通常将类型参数出现在输出位置,而逆变接口在类型上将类型参数出现在输入位置.
String
可转换为 Object
.如何使 IReadOnlyCollection
可转换为 IReadOnlyCollection
?
使 IReadOnlyCollection
在 T 中成为协变.将其标记为 out
.
考虑以下代码:
delegate void Action(T t);接口 IFoo{void M(Action<X> action);}
为什么编译器说这是无效的?
因为它无效.让我们看看为什么.
class Foo : IFoo{public void M(Action action){动作(新苹果());//苹果是水果.}}...IFoo<水果>iff = 新 Foo();IFoo<香蕉>ifb = iff;//逆变!ifb.M(banana => {banana.Peel(); });
遵循逻辑.这个程序传递一个苹果作为Banana.Peel()
的this",这显然是错误的.
编译器知道这可能发生,因此首先不允许声明接口.
如果我有更多关于方差的问题怎么办?
您应该首先阅读我关于该功能的设计和实现的文章.从底部开始;它们按时间倒序排列:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
如果您仍有问题,那么您应该在此处发布实际包含问题的问题,而不是让人们猜测问题的真正含义.
Here is my original thread:C# generic inheritance and covariance
On just my read-only interfaces, I want inheritence to work.
public delegate Boolean EnumerateItemsDelegate<out ItemType>(ItemType item);
public interface IReadOnlyCollection<out ItemType>
{
Boolean ContainsItem(ItemType item);
Array CopyToArray();
void EnumerateItems(EnumerateItemsDelegate<ItemType> enumerateDelegate);
UInt32 Count { get; }
UInt32 Capacity { get; }
}
Like this except where it compiles :-p
This is what I would like to work:
IReadOnlyCollection<String> s;
IReadOnlyCollection<Object> o = s;
There does not appear to be any question in this question, so I'll make up a few questions to answer.
Let's suppose we have some types Fruit
and Apple
and Banana
with the obvious relationships; Apple
is a kind of Fruit
, and so on.
A covariant conversion is one where the convertability of the type argument implies the convertibility of the generic type. If Apple
is convertible to Fruit
, and Bowl<Apple>
is convertible to Bowl<Fruit>
, then Bowl<T>
is covariant in T.
A contravariant conversion is a covariant conversion that reverses the direction instead of preserving it. If Eater<Fruit>
is convertible to Eater<Apple>
then Eater<T>
is contravariant in T.
Covariant type parameters are marked out
and contravariant type parameters are marked in
.
This is intended to be mnemonic: covariant interfaces typically have the type parameter appear in output positions and contravariant interfaces typeically have the type parameter appear in input positions.
Make IReadOnlyCollection<T>
covariant in T. Mark it out
.
delegate void Action<in T>(T t);
interface IFoo<in X>
{
void M(Action<X> action);
}
Because it is not valid. Let's see why.
class Foo : IFoo<Fruit>
{
public void M(Action<Fruit> action)
{
action(new Apple()); // An apple is a fruit.
}
}
...
IFoo<Fruit> iff = new Foo();
IFoo<Banana> ifb = iff; // Contravariant!
ifb.M(banana => { banana.Peel(); });
Follow the logic. This program passes an apple as the "this" of Banana.Peel()
, which is clearly wrong.
The compiler knows that this can happen, and so disallows the interface to be declared in the first place.
You should start by reading my articles on the design and implementation of the feature. Start from the bottom; they are listed in reverse chronological order:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
If you still have a question then you should post questions here that actually contain questions, instead of making people guess what the question really is.
这篇关于C# 泛型继承和协方差第 2 部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!