Substitutability of generic types in .NET
- đź“…
- đź“ť 504 words
- đź•™ 3 minutes
- 📦 .NET
- 🏷️ C#
- đź’¬ 1 response
The “is” operator
Anyone using object orientated programming soon finds themselves wanting to perform some action only if an object is of some type or implements some interface.
The easiest way is to do this is to use the is
operator. Typically it will appear something like:
object objA = FunctionToGetAnObject();
if (obj is SomeClassOrInterface)
((SomeClassOrInterface) obj).SomeMethod();
Here if obj_A
is of a type that implements SomeClassOrInterface anywhere in its inheritance tree then SomeMethod
of SomeClassOrInterface
will be called.
Test substitution with generic types
Now lets say we have our own generic type — here’s one to illustrate a point;
public class DamoClass<T> {
public T GetProperty { get { ... } }
public T SetProperty { set { ... } }
public bool IsValid { return true; }
}
If we want to check obj_A
supports DamoClass<T>
but we don’t care what type T is you might expect to be able to perform;
if (objA is DamoClass)
But that results in a compilation error — you can’t reference a generic class without specifying the type parameters regardless of whether you care about them or not. You might then try;
if (objA is DamoClass<object>)
After all every class inherits from object
. This compiles fine but at runtime if objA
is of any type other than object
, e.g. DamoClass<string>
it will return false.
Why?
The following might be what you had in mind;
if (objA is DamoClass<object>) {
((DamoClass<object>) objA).IsValid();
object test = ((DamoClass<object>) objA).GetProperty;
}
Which looks fine but if .NET allowed that then how would it prevent;
if (objA is DamoClass<object>)
((DamoClass<object>) objA).SetProperty = 11;
When objA.AssociatedObject
might well be something other than an integer? It can’t — so it doesn’t.
Solution
The solution is to split your generic class into two classes.
The first contains your non-generic methods and properties and the second inherits from the first adding all the generic specialisation. The good news is that they can even have the same name.
public class DamoClass {
public object GetProperty { get { ... } }
public bool IsValid { return true; }
}
public class DamoClass<T> : DamoClass {
public T SetProperty { set { ... } }
}
Then you are free to do;
if (objA is DamoClass) {
((DamoClass) objA).IsValid();
object test = ((DamoClass) objA).GetProperty;
}
Indeed .NET itself uses this technique for IEnumerable
and IEnumerable<T>
.
One drawback with this technique is that you can’t redefine the type of a member in the subclass — maybe that’ll make C# 3.0.
[)amien
1 response to Substitutability of generic types in .NET
Generally I treat this problem with some caution — often needing to perform conditional behaviour based on typeof() or equivalent is a sign that logic may be in the wrong place. Often this behaviour can be pushed down to the objects themselves through some more generic concept or event behaviour and let polymorphism deal with it. Another way, appropriate if the algorithm is designed to be external to the classes themselves (perhaps because it is pluggable) is with a visitor pattern, where there are multiple overloaded visit(T obj) methods — code flow naturally follows the implementation for the given type.
Whatever the way, although I do very occasionally use typeof() style logic, I generally feel uncomfortable about it since it normally means I’m not thinking about something the right way. I won’t say I’ve never done it, though ;)