这是我的原始主题: C#泛型继承和协方差
在我的只读接口上,我希望继承工作.
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; }
}
Run Code Online (Sandbox Code Playgroud)
像这样编译除外:-p
这就是我想要的工作:
IReadOnlyCollection<String> s;
IReadOnlyCollection<Object> o = s;
Run Code Online (Sandbox Code Playgroud)
这个问题似乎没有任何问题,所以我会回答几个问题.
什么是协变转换?
让我们假设我们有一些类型Fruit,Apple并且Banana有明显的关系; Apple是一种Fruit,等等.
协变转换是类型参数的可转换性意味着泛型类型的可转换性的转换.如果Apple是可转换为Fruit,并且Bowl<Apple>可以转换为Bowl<Fruit>,那么Bowl<T>在T中是协变的.
什么是逆变?
逆变换是一种协变转换,它反转方向而不是保留它.如果Eater<Fruit>是可兑换的Eater<Apple>那么Eater<T>在T中是逆变的.
如何将接口或委托标记为其类型参数中的协变或逆变?
标记协变类型参数并标记out逆变类型参数in.
这是助记符:协变接口通常在输出位置出现类型参数,而逆变接口通常在输入位置出现类型参数.
String可转换为Object.我怎样才能IReadOnlyCollection<String>兑换成IReadOnlyCollection<Object>?
IReadOnlyCollection<T>在T中做出协变.标记它out.
请考虑以下代码:
delegate void Action<in T>(T t);
interface IFoo<in X>
{
void M(Action<X> action);
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器说这是无效的?
因为它无效.让我们看看为什么.
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(); });
Run Code Online (Sandbox Code Playgroud)
遵循逻辑.这个程序通过一个苹果作为"这个" Banana.Peel(),这显然是错误的.
编译器知道这可能发生,因此不允许首先声明接口.
如果我对方差有更多疑问,该怎么办?
您应该首先阅读我关于该功能的设计和实现的文章.从底部开始; 它们以反向时间顺序列出:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
如果你还有问题,那么你应该在这里发布实际上包含问题的问题,而不是让人们猜出问题到底是什么.