问题描述
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);
}
}
这显然没有因为<$ C编译$ C> foo.Children.Add(小孩);
我不知道,如果上面的代码是最的明确的方式来证明什么,我想做的事情,所以我会尽量用简单的英语解释:
I'm not sure if the above code is the most clear way to demonstrate what I want to do, so I will try to explain in plain English:
我想有一个类,其子女对象的能力在的ISet
相同的通用类型。因此,如果我也有 VAR孩子=新AnimalWrapper<爬行动物>();
将在编译时,未能做到 foo.Children。添加(子);
,因为爬虫
不,不从哺乳动物
继承。但是,很显然,即使它派生,如上图所示,这是行不通的。
I want the ability to have a class whose Children objects are in an ISet
of the same generic type. Thus, if I also had var child = new AnimalWrapper<Reptile>();
it would, at compile time, fail to do foo.Children.Add(child);
because Reptile
is not and does not inherit from Mammal
. However, obviously, even if it's derived, as shown above, it doesn't work.
最终,它会是不错的能够说的ISet< AnimalWrapper<动物>>巴兹=新的HashSet< AnimalWrapper<动物>>();
然后添加新AnimalWrapper<哺乳动物GT;()
来那一套,而新AnimalWrapper<&爬虫GT;()
同一组。而他们的孩子将有一个属性孩子
这是一个的ISet< AnimalWrapper< T>>
其中,这是它自己的类型在某种程度上,如上所述。
Ultimately, it'd be nice to be able to say ISet<AnimalWrapper<Animal>> baz = new HashSet<AnimalWrapper<Animal>>();
then add a new AnimalWrapper<Mammal>()
to that set, and new AnimalWrapper<Reptile>()
to the same set. And their children would have a property Children
that's an ISet<AnimalWrapper<T>>
where it's of its own type, in a way, as described above.
有什么办法还是我刚刚从C#期望太高了?哎呀我混淆我自己。 :)
Is there any way or am I just expecting too much from C#? Heck I'm confusing myself. :)
修改确定,所以我几乎想通了这一点,没有 AnimalWrapper
,但与基 IAnimal
接口,它几乎可以工作:
Ok, so I almost figured this out, without AnimalWrapper
, but with a base IAnimal
interface, it could almost work:
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.
}
}
推荐答案
的主要问题是,有点过于简单,在协方差上溯造型(和逆变于ISET)
The main problem is, a bit oversimplified, in covariance upcasting (and contravariance with the ISet)
尝试这种方式...
abstract class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
class Reptile : Animal { }
interface INode<out T> where T : Animal
{
T MySelf { get; }
IEnumerable<INode<T>> Children { get; }
}
class Node<T> : INode<T>
where T : Animal
{
public Node() { this.Children = new HashSet<INode<T>>(); }
public T MySelf { get; set; }
public ISet<INode<T>> Children { get; set; }
IEnumerable<INode<T>> INode<T>.Children { get { return this.Children; } }
}
class Program
{
static void Main(string[] args)
{
// this is a 'typical' setup - to test compiler 'denial' for the Reptile type...
Node<Mammal> tree = new Node<Mammal>();
tree.MySelf = new Mammal();
var node1 = new Node<Mammal>();
tree.Children.Add(node1);
var node2 = new Node<Dog>();
tree.Children.Add(node2);
var node3 = new Node<Reptile>();
// tree.Children.Add(node3); // this fails to compile
// ...and similar just more 'open' - if you 'collect' animals, all are welcome
Node<Animal> animals = new Node<Animal>();
animals.MySelf = new Mammal();
INode<Mammal> mamals = new Node<Mammal>();
animals.Children.Add(mamals);
var dogs = new Node<Dog>();
animals.Children.Add(dogs);
INode<Animal> reptiles = new Node<Reptile>();
animals.Children.Add(reptiles);
}
}
(查找评论)
(look up the comments)
这并不意味着它会在你的现实生活中的情况下工作 - 因为这需要一些'设计重构,使之与更复杂的结构(如果可能)的工作。
This doesn't mean it'd work in your real-life case - as this requires some 'design refactoring' to keep it working with a more complex structure (if possible).
...只是快,我会试着解释一些后,如果需要的
...just fast, I'll try to explain some more later if needed
这篇关于如何使包含一组只有自己的类型或亚型儿童泛型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!