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.
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...
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With