如何使包含一组只有自己的类型或亚型儿童泛型类? [英] How to make generic class that contains a Set of only its own type or subtypes as Children?

查看:127
本文介绍了如何使包含一组只有自己的类型或亚型儿童泛型类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这篇关于如何使包含一组只有自己的类型或亚型儿童泛型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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