C# – Decorator with generic base class

cgenerics

A co-worker of mine asked me last week if it were possible in C# to extend a generic class from its generic parameter. He said it was possible in C++.
What he wanted makes actually sense. He wanted a generic decorator to annotate an arbitrary class with additional information. Something like:

public class Decorator<T> : T
{
    public object AdditionalInformation {get:set;}
}

So that he can now use this generic decorator everywhere instead of T.

The most similar thing I could come with was a container class with the original object, the additional information and an implicit conversion.

public class Decorator<T>
{
    private readonly T _instance;

    public Decorator(T instance)
    {
        _instance = instance;
    }

    public T Instance
    {
        get { return _instance; }
    }
    public object AdditionalInformation { get; set; }

    public static implicit operator T(Decorator<T> deco)
    {
        return deco._instance;
    }
}

But this is not the same because the implicit conversion is only one way. He cannot use it, for example, as a return type of a method because the additional information would be lost after he implicit conversion.

Does anybody have a better idea?

Best Answer

If you can derive all decorable classes from some base class, then you can try to store decorators in that base class and make its info recoverable. Here is sample code that is guaranteed to contain some errors, but you can get the idea.

public class Decorable
{
    Dictionary<Type,object> decors = new Dictionary<Type,object>();
    public void AddDecorator<D>(D decor) { decors[typeof(D)] = decor; }
    public D GetDecorator<D>()
    {
        object value;
        if (decors.TryGetValue(typeof(D), out value))
            return (D)value;
        else
            return default(D);
    }

}

public class Decorator<T> where T: class, Decorable
{
    private readonly T _instance;
    public Decorator(T instance)
    {
        _instance = instance;
        instance.AddDecorator(this);
    }

    public T Instance
    {
        get { return _instance; }
    }

    public object AdditionalInformation { get; set; }
}
// use it like this
Decorator<MyClass> myDecor = myObj.GetDecorator<Decorator<MyClass>>();

If you cannot derive, then you must store info in some static class. But, as wcoenen commented, you would need to clear that info or you'd get memory leaks. Clearing is error prone and not always possible, so it's better to go with the first approach. For example (not thread safe, you must add locking if you plan to use it in multithreaded apps):

static public class Decorators
{
    static Dictionary<object,Dictionary<Type,object>> instance = new Dictionary<object,Dictionary<Type,object>>();
    public static void AddDecorator<T,D>(this T obj, D decor)
    {
        Dictionary<Type,object> d;
        if (!instance.TryGetValue(obj, out d))
        {
            d = new Dictionary<Type,object>();       
            instance.Add(obj, d);
        }
        d[typeof(D)]=decor;
    }

    public static D GetDecorator<T,D>(this T obj)
    {
        // here must be double TryGetValue, but I leave it to you to add it  
        return (D) instance[obj][typeof(D)];
    }

    public static T ClearDecorators(this T obj) { instance.remove(obj); }

}

// Decorator<T> code stays the same, but without type constraint