开发者

Casting, Generics, and Subtypes

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.


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.


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.


Im sorry if I dont get the bigger picture here, but you can make DatabaseEntity<T> a seperate Generic class (a static one may be), without deriving the Parent from it.

This arrangement would allow using all the CRUD operations defined with DatabaseEntity<T> with any of the classes you might have.

P.S.: Please dont flame me if I've missed out something obvious, I'd rather appriciate some clarification so that I can learn better.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜