C# 泛型继承和协方差第 2 部分 [英] C# generic inheritance and covariance part 2
问题描述
这是我的原帖:C#泛型继承和协方差
仅在我的只读接口上,我希望继承工作.
public delegate Boolean EnumerateItemsDelegate(ItemType item);公共接口 IReadOnlyCollection{Boolean containsItem(ItemType item);数组复制到数组();void EnumerateItems(EnumerateItemsDelegate enumerateDelegate);UInt32 计数 { 得到;}UInt32容量{得到;}}
像这样,除了编译的地方:-p
这就是我想要的工作:
IReadOnlyCollections;IReadOnlyCollection<对象>o = 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.
What is a covariant conversion?
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.
What is a contravariant conversion?
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.
How do I mark an interface or delegate as being covariant or contravariant in its type parameters?
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.
String
is convertible toObject
. How can I makeIReadOnlyCollection<String>
convertible toIReadOnlyCollection<Object>
?
Make IReadOnlyCollection<T>
covariant in T. Mark it out
.
Consider the following code:
delegate void Action<in T>(T t);
interface IFoo<in X>
{
void M(Action<X> action);
}
Why does the compiler say that this is not valid?
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.
What should I do if I have more questions about variance?
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 部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!