2012-10-26 124 views
5

低垂考虑下面的代码:如何强制仿制药

class Animal 
{ } 

class Dog : Animal 
{ } 

class Cage<T> 
{ 
    private T animal; 

    public Cage(T animal) 
    { 
     this.animal = animal; 
    } 

    public T Animal 
    { 
     get { return animal;} 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Dog dog = new Dog(); 
     Cage<Animal> animalCage = new Cage<Animal>(dog); 
     Cage<Dog> dogCage = (Cage<Dog>)animalCage; 
    } 
} 

我怎样才能解决办法,最后编译器错误(转换从animalCage到dogCage)?

在我的代码我知道笼子里有一只狗,但我无法找到一个方法来施展它。是我创建一个转换器并创建一个新的Cage <Dog>实例的一个例子Cage <Animal>

+0

您可能知道笼子包含一只狗,但* type system *没有。由于泛型参数在编译过程中被删除,Java泛型会让您发出警告,但CLR泛型会保留在运行时。 –

+0

你是对的......我的问题是,如果有一个特殊的声明(或c#关键字)告诉编译器“推我”:) – user1778378

+0

没有这样的运气 - 没有办法在运行时关闭CLR通用类型强制。 –

回答

0

您可以添加generic constraint

class Cage<T> where T : Animal 

,然后就从你的方法

public Animal Animal 
{ 
    get { return animal;} 
} 

通用约束告知编译器,有对可提供的类型限制返回的基类对于T。如果你提供其他的东西,例如Cage<object>,您将收到编译时错误。

+1

您的解决方案不能解决问题。编译器仍然收到错误无法将'Cage '转换为'Cage ' – user1778378

2

这将工作的一般差异,除了T通常应该是协变(因为它是一个输出),你试图以逆变方式使用它。此外,差异不适用于类,只适用于接口和委托,因此您需要定义一个ICage<T>

协方差会允许在其他方向施放:您可以将ICage<Dog>施放到ICage<Animal>。逆变将导致矛盾,因为您将能够试图将包含CatCage<Animal>投射到Cage<Dog>,呈现get_Animal不合格。

数组是协变的,以及:你可以施放Dog[]Animal[],但你不能施放Animal[]Dog[]即使你知道它仅包含狗。

我想到的下一件事是定义一个明确的转换运算符,但是these can't be generic

最后,你需要构建一个新的Cage<Dog>来完成这项工作。

+0

(Co)方差应用于接口,而不是类。你可能想修改你的答案来反映这一点。 –

+1

我想到了一点:无论方差限于代表和接口,他所寻找的是一个不安全的缩小演员阵容,并且允许它会导致类型系统中的矛盾。 –

4

问题1:你不能把一个Cage<Animal>实例为Cage<Dog>实例,需要一个Cage<Dog>实例(或更具体类型的实例),其参考存储在更少的特定类型的变量。

变化

Cage<Animal> animalCage = new Cage<Animal>(dog); 
Cage<Dog> dogCage = (Cage<Dog>)animalCage; 

Cage<Animal> animalCage = new Cage<Dog>(dog); 
Cage<Dog> dogCage = (Cage<Dog>)animalCage; 

问题2:不能存储在Cage<Animal>变量参照Cage<Dog>实例,因为类不支持合作/逆变。

变化

class Cage<T> 
{ 
    ... 

interface ICage<out T> 
{ 
    T Animal { get; } 
} 

class Cage<T> : ICage<T> 
{ 

Cage<Animal> animalCage = new Cage<Dog>(dog); 
Cage<Dog> dogCage = (Cage<Dog>)animalCage; 

ICage<Animal> animalCage = new Cage<Dog>(dog); 
ICage<Dog> dogCage = (Cage<Dog>)animalCage; 

然后它的工作。 (如果您不更改new Cage<Animal>new Cage<Dog>,则会在运行时发生强制性异常。)

+0

是的,这个工程,但不幸的是我不知道我可以切换到接口。 Cage对象必须通过WCF服务,并且接口在通用“对象”中解析(与KnownTypes相关的问题...)。对不起,这是一个简化大问题的尝试:) – user1778378

+0

我不知道我们如何提供帮助。你需要改变设计中的某些东西,但不知道更多,很难提出任何建议。 – dtb

+0

@ user1778378 KnownTypes相关的问题?您可以继承['DataContractResolver'](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.datacontractresolver.aspx)以控制实际运行时类型与XML的映射。 –