Como fazer classe genérica que contém um conjunto de apenas seu próprio tipo ou subtipos como filhos?

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);
    }
}

Isso obviamente não compila por causa defoo.Children.Add(child);

Não tenho certeza se o código acima é o maisClaro maneira de demonstrar o que eu quero fazer, então vou tentar explicar em Inglês:

Eu quero a capacidade de ter uma classe cujos objetos filhos estão em umISet do mesmo tipo genérico. Assim, se eu também tivessevar child = new AnimalWrapper<Reptile>(); seria, em tempo de compilação, não conseguirfoo.Children.Add(child); PorqueReptile não é e não herda deMammal. No entanto, obviamente, mesmo que seja derivado, como mostrado acima, não funciona.

Em última análise, seria bom poder dizerISet<AnimalWrapper<Animal>> baz = new HashSet<AnimalWrapper<Animal>>(); em seguida, adicione umnew AnimalWrapper<Mammal>() para esse conjunto, enew AnimalWrapper<Reptile>() para o mesmo conjunto. E seus filhos teriam uma propriedadeChildren isso é umISet<AnimalWrapper<T>> onde é de seu próprio tipo, de certa forma, como descrito acima.

Existe alguma maneira ou estou apenas esperando muito de c #? Eu estou me confundindo. :)

Editar: Ok, então eu quase percebi isso, semAnimalWrapper, mas com uma baseIAnimal interface, quase poderia funcionar:

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.
    }
}

questionAnswers(2)

yourAnswerToTheQuestion