Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheritance and shared static fields

Suppose I have a Generic abstract class that provides some default constructor functionality so you don't have to repeat the code in your inherited classes:

public abstract class Base<TKey, TValue>
{
    private static readonly IDictionary<TKey, Base<TKey, TValue>> Values = new Dictionary<TKey, Base<TKey, TValue>>();

    public TKey Key { get; private set; }
    public TValue Value { get; private set; }

    protected Base(TKey key, TValue value)
    {
        this.Key = key;
        this.Value = value;

        Values.Add(key, this);
    }
}

Now the problem is that when I write two inherited classes like:

public sealed class One : Base<string, string>
{
    public static readonly One Default = new One("DEF", "Default value");
    public static readonly One Invalid = new One("", "Invalid value");

    private One(string key, string value) : base(key, value) {}
}

public sealed class Two : Base<string, string>
{
    public static readonly Two EU = new Two("EU", "European Union");
    public static readonly Two USA = new Two("", "United States of America");

    private Two(string key, string value) : base(key, value) {}
}

As you can see these two are sort of type-safe enumerations really. They only provide predefined values and they can't be instantiated for any other purpose.

Question

The problem is because both of these inherited classes use the same generic types with base class which is Base<string, string>. And the way that generic classes and static fields work is that for each generic type (or combination when more than one) a new static field is created.

In my case the combination is string, string that's why there's only one base class static field and it holds 4 values instead of having two static fields each with 2 values.

How do I overcome this issue and separate those while still keeping this functionality on the base class so I don't repeat my code?

Changing field from static to instance won't work, because they I'll end up with 4 instances each holding just one value...

like image 985
Robert Koritnik Avatar asked Jun 19 '12 15:06

Robert Koritnik


1 Answers

This will work. I believe it's known as the curiously recurring template pattern, but don't quote me on that

public abstract class Base<TSelf, TKey, TValue>
{
    private static readonly IDictionary<TKey, Base<TSelf, TKey, TValue>> Values = 
        new Dictionary<TKey, Base<TSelf, TKey, TValue>>();

    public TKey Key { get; private set; }
    public TValue Value { get; private set; }

    protected Base(TKey key, TValue value)
    {
        this.Key = key;
        this.Value = value;

        Values.Add(key, this);
    }
}


public sealed class One : Base<One, string, string>
{
    public static readonly One Default = new One("DEF", "Default value");
    public static readonly One Invalid = new One("", "Invalid value");

    private One(string key, string value) : base(key, value) { }
}

public sealed class Two : Base<Two, string, string>
{
    public static readonly Two EU = new Two("EU", "European Union");
    public static readonly Two USA = new Two("", "United States of America");

    private Two(string key, string value) : base(key, value) { }
}

The 'curious' part is that the definitions of One and Two are allowed to use themselves as type parameters to themselves!

like image 133
AakashM Avatar answered Sep 22 '22 02:09

AakashM