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