Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting, Generics, and Subtypes

Tags:

c#

generics

In trying to implement the repository pattern I've run into a minor problem that I'm concerned actually belies bigger issues.

I've got a DatabaseEntity<T> which I'm using to handle all the basic CRUD operations and from which all other classes that need to be stored in a database will descend from. It is working fine for classes that inherit directly from it, however when using it with classes that have an intermediate parent I've run into a problem.

Suppose I have three other classes, Parent, ChildA and ChildB and and the inheritance looks like:

DatabaseEntity
          |
     Parent
     |        |
ChildA ChildB

Also suppose that DatabaseEntity<T> has a method with the following signature:

public static T FindBy(int id)  

The issue I'm having is when I try something like:

ChildA Foo = ChildA.FindBy(SomeID);

I get a compiler error telling me that there's no implicit conversion from a Parent to a ChildA. This is because Parent is the class that's being passed in for the type parameter to DatabaseEntity for both ChildA and ChildB. Easy fix I think, just add a type parameter to Parent thus passing through the appropriate type. Only wait a second, then I'll have to explicitly define the subtype any time I'm using Parent which ruins any polymorphism. No, on second thought maybe that's not such a great fix.

I think that I could just drop the type parameter on the class DatabaseEntity itself and have each method require a type parameter but then I'd have to do something like:

ChildA Foo = ChildA.FindBy<ChildA>(SomeID);

While that compiles, it seems less clean and certainly requires more typing. Visual Studio asks if I'm missing a cast and while its true I could just cast my first example its only a matter of time before I accidentally type out:

ChildB Foo = (ChildB) ChildA.FindBy(SomeID)

I'm not especially pleased with any of the solutions I've thought of so far and I'm hoping someone here can point out an elegant one that I've missed.

like image 243
Trajanus Avatar asked Feb 17 '11 02:02

Trajanus


People also ask

What is generic type casting?

In the general case, a generic type could be both a supplier and a consumer of its type parameters, which means that the type we get by casting the type parameter (up or down) cannot be either a subtype or a supertype of the original: they are unrelated types that cannot be cast between, which is exactly why the Java ...

What is a subtype in Java?

What is subtyping? Subtyping is a key feature of object-oriented programming languages such as Java. In Java, Sis a subtype of T if S extends or implements T. Subtyping is transitive, meaning that if R is a subtype of S, then R is also a subtype of T (T is the super type of both Sand R).

Does generics eliminate use of casting?

As mentioned previously, generics can eliminate the requirement for casting.


2 Answers

I think that making Parent a generic class is the way to go. You didn't explain what exactly is the purpose of the type T in your example, but I suppose you want it to be the actual type of the entity, so for example your Parent would inherit Entity<Parent>.

You can still write polymorphic code in this scenario - you just have to use generics:

static void Foo<T>(Parent<T> p) where T : Parent<T>
{
  Parent<T> entity = p.Find();
}

This method can be called with both ChildA and ChildB. The only tricky aspect is that you cannot actually create an instance of Parent<Parent<...>> (because the dots would have to be replaced with more nested Parent<...> types), but you can write somthing like this:

class ParentFix : Parent<ParentFix> { }

.. then you can pass instances of ParentFix to the Foo method as well.

like image 167
Tomas Petricek Avatar answered Sep 27 '22 21:09

Tomas Petricek


I know this isn't the answer you're looking for, but I would recommend using a solid off-the-shelf ORM, like Entity Framework 4. It supports inheritance out of the box, and it's basic, fundamental usage is a repository.

I think you're in for a lot of pain if you try to roll this yourself.

like image 45
Adam Rackis Avatar answered Sep 27 '22 21:09

Adam Rackis