我有以下代码块作为我遇到的问题的简化示例。但是我收到一个错误消息,声称我无法将一种类型转换为另一种类型。我使用LINQPad进行了测试。

void Main()
{
    LivingThing<Appendage> mysteryAnimal = new Cat();
}

public class Appendage { }
public class Paw : Appendage { }

public class LivingThing<TExtremity> where TExtremity : Appendage { }
public class Animal<TExtremity> : LivingThing<TExtremity> where TExtremity : Appendage { }
public class Cat : Animal<Paw> { }


当我知道Cat的定义使用的是CatLivingThing<Appendage>子类时,为什么不能将LivingThing转换为Appendage

最佳答案

通过向其中一个类添加方法,可以更容易地看到为什么您尝试做的事情如果不做一些修改就无法工作:

public class LivingThing<TExtremity> where TExtremity : Appendage {
    private TExtremity extremity;
    public void SetExtremity(TExtremity e) {
        extremity = e;
    }
}


现在,让我们想象一下C#可以让您完成分配。然后,它应该让您执行此操作:

public class Hand : Appendage { }
...
// Let's pretend this works
LivingThing<Appendage> cat = new Cat();
// Now that C# let us do the assignment above, it must allow this too,
// because Cat is a LivingThing and Hand is an Appendage:
cat.SetExtremity(new Hand());


糟糕,我们有一只手扶着的猫! C#不应该让我们这样做。

但是,如果LivingThing具有返回TExtremity的方法,则可以做您想做的事情。 C#提供了用于定义继承层次结构的方法,这些层次结构使您可以按照尝试的方式灵活地分配。这是修改后的代码,可以正常工作:

void Main()
{
    ILivingThing<Appendage> mysteryAnimal = new Cat();
}

public class Appendage { }
public class Paw : Appendage { }

public interface ILivingThing<out TExtremity> where TExtremity : Appendage { }
// You have a choice of keeping Animal a class. If you do, the assignment
// Animal<Appendage> mysteryAnimal = new Cat()
// would be prohibited.
public interface IAnimal<TExtremity> : ILivingThing<out TExtremity> where TExtremity : Appendage { }
public class Cat : Animal<Paw> { }


有一个陷阱:ILivingThing<TExtremity>IAnimal<TExtremity>都不允许具有TExtremity类型的可设置属性或以TExtremity作为参数的方法。

09-06 12:54