I'm running into a situation where I have two levels of polymorphism, one within the other, in a parent/child hierarchy.
I think this is best explained by a simple example:
class Group
{
public IList<Person> People { get; set; }
}
class SpecialGroup : Group
{
public IList<SpecialPerson> People { get; set; }
}
class Person {}
class SpecialPerson : Person {}
So a Group has a list of Person objects, while a specialized Group (SpecialGroup) has a specialized list of Person (SpecialPerson) objects.
This compiles, but I get a warning saying I should use the "new" keyword on SpecialGroup.People, because it hides the Group.People property.
I understand what that means, but perhaps I don't fully comprehend how you would model something like this correctly in C# to begin with. Any thoughts on how to model this in a better way?
Also, any idea how this would play with NHibernate? I'm not sure using the "new" keyword will cut it, since the Group.People property would already be mapped with a different type. Is there a better way to model this, in a way that is compatible with NH?
Okay, I thought of a way to model this using generics:
abstract class AbstractGroup<PersonType>
where PersonType : Person
{
public IList<PersonType> People { get; set; }
}
class Group : AbstractGroup<Person>
{}
class SpecialGroup : AbstractGroup<SpecialPerson>
{}
class Person {}
class SpecialPerson : Person {}
I think this does what I want? Now Person can share traits with SpecialPerson, but only a SpecialPerson can be added to a SpecialGroup. The AbstractGroup base-type can model the traits common to any Group.
Now the question is, will NH blow up if I try to map this?
For the record, it appears some people have successfully used query-over with generic classes - for HQL queries (my use-case) this is unsupported.
Another approach that occurred to me, is to simply hide the parent's implementation of a property, e.g. using the "new" keyword for an overriding property in a subclass - the following thread discusses why that won't work either:
NHibernate: Table Per Subclass Mapping and the New Keyword
Conclusion thus far: run-time checking and exceptions, as proposed by @empi below.