Today, I am writing about a design problem related to C# generics that I’ve seen arise a few times. The problem occurs when we need to manipulate a generic class given a reference to its non-generic base class. For example, if a generic class Node<T> inherits from a non-generic class Node, and we are holding a Node reference to a Node<T> object, we cannot just cast the object to Node<T> because we do not have access to T.

I realize that the description is a bit abstract; let’s look at an example right away! It may look like a bit of code, but the classes are very simple and do just what you’d expect:

  1. // Abstract node in a linked list
  2. public abstract class Node {
  3.         private Node m_next;
  4.         public Node Next { get { return m_next; } }
  5.         public Node(Node next) { m_next = next; }
  6. }    
  7.  
  8. // Node in a linked list. Different nodes in the same list may carry data
  9. // of different types.
  10. public class Node<T> : Node {
  11.         private T m_data;
  12.         public T Data { get { return m_data;    } }
  13.         public Node<T>(T data, Node next) : base(next) {
  14.                 m_data = data;
  15.         }
  16. }    
  17.  
  18. // Abstract pair.
  19. public abstract class Pair { }    
  20.  
  21. // Pair containing two values, possibly of different types.
  22. public class Pair<TFirst, TSecond> : Pair {
  23.         private TFirst m_first;
  24.         private TSecond m_second;
  25.         public Pair(TFirst first, TSecond second) {
  26.                 m_first = first;
  27.                 m_second = second;
  28.         }
  29. }

Here, Node is a node in a linked list where each node may contain a different type of data. Pair is just a pair of two values.

Now, suppose that we want to implement this method:

  1. // Returns a pair containing the first two values from a linked list
  2. public static Pair FirstTwoValues(Node node) {
  3.         if (node == null) throw new ArgumentException();
  4.         if (node.Next == null) throw new ArgumentException();    
  5.  
  6.         // Compilation error:
  7.         return new Pair<U,V>((Node<U>)node, (Node<V>)node.Next);
  8. }

Unfortunately, what I wrote on the last line is not valid C# because we cannot introduce a type variable in a cast. It is clear what we need to do: we have two Node objects which we assume to be instances of Node<U> and Node<V> respectively, and we would like to invoke some generic method - in this case a Pair<U,V> constructor - using both U and V as generic type parameters for the method. So how can we implement this?

Solution 1
The easiest solution is to use big nested if statements:

  1. public static Pair FirstTwoValues(Node node) {
  2.         // [...]
  3.         if (node is Node<int>) {
  4.                 if (node.Next is Node<int>) return new Pair<int,int>(
  5.                         (Node<int>)node, (Node<int>)node.Next);
  6.                 }
  7.                 else if (node.Next is Node<string>)
  8.                 …
  9.         }
  10.         else if (node is Node<string>)
  11. }

Obviously, this solution only works when the set of possible node data is constrained and very small, and even then the code is quite ugly.

Solution 2

Another possible solution is to use reflection. Reflection is very powerful, but it should be considered a last-resort technique because of its huge negative impact on the performance and general ugliness.

Solution 3

There is a third solution, that is in many cases preferable over the two I already mentioned. One way to “get access” to the type parameter T of the Node<T> is through a virtual method call. Node implements an abstract method, which Node<T> overrides. Calling the method on a Node reference results in that method executing in the context of Node<T> and we finally get access to that elusive type parameter T!

But, what if we need to get access to multiple generic type parameters coming from multiple objects, just like when trying to call a Pair<U,V> constructor given Node<U> and Node<V>? We can have multiple chained virtual methods, where each one fixes one of the generic parameters:

  1. public abstract class Node {
  2.         private Node m_next;
  3.         public Node Next { get { return m_next; } }
  4.         public Node(Node next) { m_next = next; }
  5.         public abstract Pair ConstructPair(Node other);
  6.         public abstract Pair ConstructPair<TFirst>(Node<TFirst> other);
  7. }    
  8.  
  9. public class Node<T> : Node {
  10.         private T m_data;
  11.         public T Data { get { return m_data; } }
  12.         public Node<T>(T data, Node next) : base(next) {
  13.                 m_data = data;
  14.         }    
  15.  
  16.         public override Pair ConstructPair(Node secondNode) {
  17.                 return other.ConstructPair<T>(this);
  18.         }    
  19.  
  20.         public override Pair ConstructPair<TFirst>(Node<TFirst> firstNode) {
  21.                 return new Pair<TFirst,T>(firstNode, this);
  22.         }
  23. }

Unfortunately, in order for this solution to be applicable, we need to have control over all types that could possibly be specified as the generic parameter, and they also need to share a common base class or implement a common interface that we can modify. Another disadvantage is that the type parameter class (in our case, Node) needs to know how to perform a possibly unrelated action (in our case, to construct a Pair). This may or may not be ideal from the design perspective.

Despite the disadvantages, I personally found this little trick quite useful. The problems I applied it to were related to abstract syntax tree manipulations, but I would expect similar issues to arise in other problem domains like data structures, data binding, etc. If you run into a similar design problem with generics, let me know whether you were able to apply this trick or not.

Share/Save/Bookmark