Compartilhar via


Generics: The “Self Referencing Generics” pattern

OK, so it isn’t really a sensible name for a pattern. In reality, this post is just about a useful technique to use when developing with generics that initially can feel a little counter intuitive. I’ve found many uses for it, so I think it is worth sharing.

Putting the basics in place, remember that .NET 2.0 introduced the concept of generics, whereby I can define a type that has an additional “type parameter”. This means that I can vary aspects of my implementation class in a strongly typed way.

For example, the following defines a type that can be instantiated to store a value of any type;

public class ValueHolder<T>

{

    private T _value;

    public ValueHolder(T value)

    {

        _value = value;

    }

    public T Value

    {

        get

        {

            return _value;

        }

    }

}

I would then create instances of ValueHolder<int>, ValueHolder<string>, and so on.

To the unaccustomed eye, this can seem strange, but once you understand the basics it is straightforward. If you need to brush up on Generics I’d recommend the “Introduction to Generics” from the C# Programming Guide.

Self-referencing Generic Types

So let’s introduce the concept of inheriting from a generic type. For example, I could subclass ValueHolder in the following ways;

public class SubValueHolder : ValueHolder<string>

{

    // implementation

}

public class SubValueHolderToo<T> : ValueHolder<T>

{

    // implementation

}

The first hard-codes the “string” implementation of ValueHolder, and the second allows the user of the class to specify the generic type parameter still. So the first example is now a concrete type definition with no generic type parameter... so could I supply it as the generic type parameter to the ValueHolder base class? Rather than repeat that pseudo-nonsense, let me show you what I mean;

public class SubValueHolderThree : ValueHolder<SubValueHolderThree>

{

    // implementation

}

In other words, SubValueHolderThree is both defined and used as a type parameter on the same line. And the answer is “yes, you can”! This means that lines such as the following are valid code;

SubValueHolderThree three = new SubValueHolderThree();

// ... setup code removed...

three.Value.Value.Value.Value.Value = myValue;

... and of course the use of this nested Value property can repeat to your heart’s content. Useful huh?

No? What do you mean?! Well I guess you have a point...

Useful Self-Referencing Generic Types (1)!

Chances are the previous example isn’t quite as useful as you were hoping. However, there are two examples where this technique is very useful. The first example is when a repeating pattern really is what you want;

public class LinkedListBase<T>

{

    public T Next { get; set; }

    public T Previous { get; set; }

}

public class PersonLinkedList : LinkedListBase<PersonLinkedList>

{

    public string Name { get; set; }

    public int Age { get; set; }

}

In this scenario, we have just created a PersonLinkedList that will allow code such as the following;

PersonLinkedList personlist = new PersonLinkedList();

// ... setup code removed...

string name = personlist.Next.Previous.Next.Name;

Now with a linked list, it is logical to expect this to work, and indeed it does perfectly, allowing you to put all manner of common logic in the LinkedListBase class. Contrast this to a traditional linked list implementation with generics and you would have to define a “TheValue” property on the linked list base class, like this;

public class Person

{

    public string Name { get; set; }

    public int Age { get; set; }

}

public class OldLinkedListBase<T>

{

    public T TheValue { get; set; }

    public OldLinkedListBase<T> Next { get; set; }

    public OldLinkedListBase<T> Previous { get; set; }

}

Which means you must write code that looks like this;

OldLinkedListBase<Person> personlistToo = new OldLinkedListBase<Person>();

// ... setup code removed...

personlistToo.Next.Next.TheValue.Age = 10;

The extra requirement to access a property that contains the entity I’m after is pretty ugly, I reckon, and it doesn’t suit the scenario where the “listed” object should semantically contain the Next and Previous links (or Parent and Child on a Person object, for example).

Useful Self-Referencing Generic Types (2)!

The second useful example is when you want to implement the Singleton pattern across a common set of subclasses. Consider the following definition;

public class BaseClass<T>

{

    public static readonly T Instance = default(T);

}

public class SubClass : BaseClass<SubClass>

{

    public string Name { get; set; }

}

Using a self-reference as the generic type parameter when writing the subclass means two things; firstly we get a static Instance property that is defined as type SubClass (perfect for Singleton!), and secondly we get access to all the instance members on that single instance of SubClass. So, without writing anything else, this code will work;

SubClass.Instance.Name = "Simon";

What is even better, is that I can add as many different subclass types as I like, reusing my Singleton implementation every time. Handy, huh?

Conclusion

Well, I’m sure this has started you thinking now... and of course there must be many different applications for this approach. It isn’t a revolutionary idea, but it does demonstrate one of the less well known benefits of generics. Do let me know if you find a particularly interesting implementation for the idea.

Two little disclaimers:

1. Note that I have not discussed the requirement for managing concurrent access to data when using the Singleton pattern as that is not the point of this post, but suffice to say that the above will work but needs more work before it is real-world ready. If you’re interested in this, I’d recommend reading “Exploring the Singleton Design Pattern” and “Implementing Singleton in C#”.

2. Do you really need a Singleton? Are you sure? Are you just using it to hold global variables when you shouldn’t be, or making it easier to reference other objects, or trying to reduce the number of objects your application instantiates? If the answer is yes to any of these, I’d recommend reconsidering: Singleton is great for controlling truly shared data that needs concurrency management for updates in memory, and in general not so great for other scenarios.

Comments

  • Anonymous
    June 12, 2008
    The comment has been removed

  • Anonymous
    June 15, 2008
    After being prompted by a friend (or ex-colleague, or drinking buddy, whatever you want to be called

  • Anonymous
    September 01, 2008
    Just a point you may not know, which is that if you ever needed to convert your C# to C++/CLI, you cannot use self-referencing generic types in the latter, mainly because the C++ compiler does not allow types to be used before they're defined. Hence, your simple example BaseClass<T> has no conversion to C++/CLI.

  • Anonymous
    August 09, 2011
    Brilliant, I am wondering who is the talent invented this pattern.

  • Anonymous
    August 11, 2011
    The singleton example looks interesting, but your code would still allow me to do something like SubClass aClass = new SubClass(); which by default means it is not a true Singleton...

  • Anonymous
    August 11, 2011
    en.wikipedia.org/.../Curiously_recurring_template_pattern

  • Anonymous
    August 11, 2011
    @ ad, fair point. Just oversimplification of the sample - slap a private constructor in there and we're sorted. Simon

  • Anonymous
    August 19, 2011
    Scala has 'this.type' which does exactly the same thing - allows to return subclass-typed self references from base class methods.  Also scala has built in support for singletons via 'object' keyword.

  • Anonymous
    March 19, 2012
    default(T) for a class is 'null', thus SubClass.Instance is always null unless instantiated somehow, but without making a public constructor on SubClass, it can't be instantiated by BaseClass. I can't see how this would work?