Limitations of Polymorphic Behavior with Generics vs. Interfaces
Steve Michelotti exposes an interesting limitation of polymorphism with Generics:
In .NET 2.0, Generics is clearly the single most important language enhancement. However, to use generics to the full potential, developers should understand both the capabilities and limitations of generics as they relate specifically to polymorphism. In short, while generics do support some polymorphic behavior, the use of Interfaces should still be the preferred polymorphic mechanism in many cases.
Here's my code take on this, as a little "exercise". This is pretty "linear" so it should be fairly easy to follow. The actual demo "test" code lines are in the "class program". You can paste this into a VS.NET 2005 Console app if you want to play around with it by uncommenting some lines:
The key point is that a generic class is a type itself. The compiler doesn't care about CSharpDeveloper vs Developer, it cares about DeveloperAction vs DeveloperAction. In other words, it needs a relationship between the two DeveloperAction types, not the generic type parameters that created them.
One way to express this:
abstract class DeveloperAction
{
}
class DeveloperAction : DeveloperAction where T : Developer
{
public void DoAction(T item) { }
}
List DeveloperActionList = new List();
In order to get this to compile, we had to use a NON-generic class. And with that you get no polymorphic behavior - the abstract DeveloperAction class has no methods. In this case, there'd be no way to get at the DoAction() method without casting. That's the difference in polymorphism with generic versus non-generic classes.
The lesson learned is simple: You can get real, usable polymorphic behavior plus the benefits of Generics, provided you stick to your old friend, the interface.
In .NET 2.0, Generics is clearly the single most important language enhancement. However, to use generics to the full potential, developers should understand both the capabilities and limitations of generics as they relate specifically to polymorphism. In short, while generics do support some polymorphic behavior, the use of Interfaces should still be the preferred polymorphic mechanism in many cases.
Here's my code take on this, as a little "exercise". This is pretty "linear" so it should be fairly easy to follow. The actual demo "test" code lines are in the "class program". You can paste this into a VS.NET 2005 Console app if you want to play around with it by uncommenting some lines:
|
The key point is that a generic class is a type itself. The compiler doesn't care about CSharpDeveloper vs Developer, it cares about DeveloperAction
One way to express this:
abstract class DeveloperAction
{
}
class DeveloperAction
{
public void DoAction(T item) { }
}
List
In order to get this to compile, we had to use a NON-generic class. And with that you get no polymorphic behavior - the abstract DeveloperAction class has no methods. In this case, there'd be no way to get at the DoAction() method without casting. That's the difference in polymorphism with generic versus non-generic classes.
The lesson learned is simple: You can get real, usable polymorphic behavior plus the benefits of Generics, provided you stick to your old friend, the interface.
Hajo,
ReplyDeletegreat post but could you please use some naming convention?
DeveloperAction.DoAction() looks like you are calling static function and is quite confusing. Especially when one line lower you are using :
codeAction.DoAction().
Pawel Pabich
I suppose I could have used "Hamburger?" to make it stand out, but the line that declares codeAction comes right before its use.
ReplyDeleteSorry if it seemeed unclear. Thanks for the nice comment.