C# 泛型继承和协方差第 2 部分 [英] C# generic inheritance and covariance part 2

查看:30
本文介绍了C# 泛型继承和协方差第 2 部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的原帖:C#泛型继承和协方差

仅在我的只读接口上,我希望继承工作.

public delegate Boolean EnumerateItemsDelegate(ItemType item);公共接口 IReadOnlyCollection{Boolean containsItem(ItemType item);数组复制到数组();void EnumerateItems(EnumerateItemsDelegate enumerateDelegate);UInt32 计数 { 得到;}UInt32容量{得到;}}

像这样,除了编译的地方:-p

这就是我想要的工作:

IReadOnlyCollections;IReadOnlyCollection<对象>o = s;

解决方案

这个问题好像没有什么问题,所以我会补几个问题来回答.

<块引用>

什么是协变转换?

假设我们有一些类型 FruitAppleBanana 具有明显的关系;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 to Object. How can I make IReadOnlyCollection<String> convertible to IReadOnlyCollection<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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆