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);
}
}
This obviously doesn't compile because of foo.Children.Add(child);
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:
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.
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.
Is there any way or am I just expecting too much from C#? Heck I'm confusing myself. :)
Edit: 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.
}
}
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…