abstract class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
class Reptile : Animal { }
class AnimalWrapper<T> where T : Animal
{
public ISet<AnimalWrapper<T>> Children { get; set; }
}
class Program
{
public static void Main(string[] args)
{
var foo = new AnimalWrapper<Mammal>();
foo.Children = new HashSet<AnimalWrapper<Mammal>>();
var child = new AnimalWrapper<Dog>();
foo.Children.Add(child);
}
}
这段代码显然无法编译通过,因为 foo.Children.Add(child);
我不确定上面的代码是否是最清晰的方式来说明我想做什么,所以我会尝试用简单的英语解释:
我想要一个类,其Children对象在相同泛型类型的ISet中。因此,如果我还有var child = new AnimalWrapper<Reptile>();
,则编译时,尝试执行foo.Children.Add(child);
将失败,因为Reptile
不是Mammal
并且没有继承Mammal
。然而,即使它是派生的,如上所示,也不能正常工作。
最终,能够说ISet<AnimalWrapper<Animal>> baz = new HashSet<AnimalWrapper<Animal>>();
然后将new AnimalWrapper<Mammal>()
添加到该集合中,以及将new AnimalWrapper<Reptile>()
添加到同一集合中,这将是很好的。它们的子代将具有属性Children
,它是一个ISet<AnimalWrapper<T>>
,其中它是它自己的类型,如上所述。
有没有办法实现这一点,或者我只是对C#期望过高?该死的,我自己都搞糊涂了。
编辑:好的,所以我差不多想出了一个解决方案,没有使用AnimalWrapper
,而是使用基本的IAnimal
接口:
interface IAnimal { }
abstract class Animal<T> : IAnimal where T : Animal<T>
{
public ISet<T> Children { get; set; }
}
class Mammal : Animal<Mammal> { }
class Dog : Mammal { }
class Reptile : Animal<Reptile> { }
class Frog : Reptile { }
class Program
{
public static void Main(string[] args)
{
var animals = new HashSet<IAnimal>(); // any animal can be in this
var mammal = new Mammal();
animals.Add(mammal);
mammal.Children = new HashSet<Mammal>();
var dog = new Dog();
mammal.Children.Add(dog); // ok! a dog is a mammal
dog.Children = new HashSet<Dog>(); // in theory, OK, but compile time error
// because Dog : Mammal, and Mammal defines Animal<Mammal>, therefore Dog's
// Children is actually ISet<Mammal>, rather than ISet<Dog> (which is what
// I want, recursively apply the T in Animal.
Mammal mammal2 = new Mammal();
dog.Children.Add(mammal2); // should be verboten, but is allowed for the
// same reason above.
}
}