实现嵌套的通用接口 [英] Implementing nested generic Interfaces

查看:109
本文介绍了实现嵌套的通用接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类/接口:

  //模型
public class A:IA {}
//模型逻辑
公共类B:IB< A> {}

//模型接口
public interface IA {}
//模型逻辑接口
public interface IB< T> T:IA {}

我尝试使用以下代码创建新实例:

  IB< IA> foo = new B(); 

我收到以下错误:

 不能将类型'B'隐式转换为'IB< IA>'。存在明确的转换(您是否缺少演员?)

有人可以解释为什么是不可能的?

解决方案

好的,我们来替换 A with Fish IA with IAnimal B Aquarium ,以及 IB< T> C>的IContainer< T> 。我们将为 IContainer< T> 添加一个成员,并为 IAnimal 添加一个成员:

  // Model 
public class Fish:IAnimal {}
public class Tiger:IAnimal {}
/ / ModelLogic
公共类水族馆:IContainer< Fish>
{
public Fish Contents {get;组; }
}

//模型接口
public interface IAnimal {}
//模型逻辑接口
公共接口IContainer< T> T:IAnimal
{
T Contents {get;组; }
}

IContainer< IAnimal> foo = new Aquarium(); //为什么这是非法的?
foo.Contents = new Tiger(); //因为这是合法的!

您可以将Tiger放入foo中 - foo被键入为可容纳的容器任何动物。但是你只能将鱼放入水族馆。由于您可以在 Aquarium 上合法执行的操作与您可以在 IContainer< IAnimal>上执行的操作不同 ,类型不兼容。



您需要的功能称为 generic interface covariance ,它是由C#4支持的,但是你必须向编译器证明你永远不会把老虎放进你的鱼缸里。您想要做的是:

  //模型
公共类A:IA {}
/ / ModelLogic
public class B:IB< A> {}

//模型接口
public interface IA {}
//模型逻辑接口
public interface IB< out T>其中T:IA {}

注意 IB 。这 out 表示 T 只能用作输出,而不能用作输入。如果 T 只是一个输出,那么别人就没有办法让老虎进入该鱼缸,因为没有放入属性或方法。



我在向C#添加该功能时编写了大量博客文章;如果您对该功能的设计考虑事项感兴趣,请参阅:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/


I have the following Classes / Interfaces:

// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }

// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<T> where T : IA { }

I try to create a new instance using the following code:

IB<IA> foo = new B();

I am getting the following error:

Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)

Can someone please explain why this is not possible?

解决方案

OK, let's replace A with Fish, IA with IAnimal, B with Aquarium, and IB<T> with IContainer<T>. And we'll add a member to IContainer<T>, and a second implementation of IAnimal:

// Model
public class Fish : IAnimal { }
public class Tiger : IAnimal { }
// ModelLogic
public class Aquarium : IContainer<Fish> 
{ 
    public Fish Contents { get; set; }
}

// Model Interface
public interface IAnimal { }
// ModelLogic Interface
public interface IContainer<T> where T : IAnimal 
{ 
    T Contents { get; set; }
}

IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal?
foo.Contents = new Tiger(); // Because this is legal!

You can put a Tiger into foo -- foo is typed as a container that can contain any animal. But you can only put a Fish into an Aquarium. Since the operations you can legally perform on an Aquarium are different than the operations you can perform on an IContainer<IAnimal>, the types are not compatible.

The feature you want is called generic interface covariance and it is supported by C# 4, but you have to prove to the compiler that you will never put a tiger into your fish tank. What you want to do is:

// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }

// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<out T> where T : IA { }

Notice the covariance annotation on IB. This out means that T can only be used as an output, not as an input. If T is only an output then there is no way for someone to put a tiger into that fish tank because there is no "put into" property or method possible.

I wrote a number of blog articles while we were adding that feature to C#; if you are interested in the design considerations that went into the feature, see:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

这篇关于实现嵌套的通用接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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