Singletons, Generic & Inheritance have all child classes inherit the singleton functionality

I've got two problems. One is that I'm trying to have an abstract singleton class, that has the singleton functionality + a little extra functionality in it, but this class is also a generic (unrelated to it being singleton). I want any of it's child classes to inherit the singleton functionality without rewriting code, and also the rest of the functionality which is dependent on the generic type.

Second problem, the abstract class has a non-default constructor, that should receive a string value. This string can be determined by the class of the child-class (the class that inherits the abstract calss).

My ideas to handle this where as follows:

  • Add an abstract static method to the abstract class that returns a string parameter, so that every derived class will implement it, hence any non-abstract instance of the class will work fine. Not possible because static methods cannot be abstract.
  • Create an interface with a static method that returns the string, and make sure that the generic type inherits from that interface. Then when instantiating the singleton, it will call T.GetTheString() to pass as a parameter to the constructor. Not possible since interfaces may not have static methods.

Any ideas?

Here's some simplified code that explains my problem:

public abstract class NamedObject<T> {
    private static NamedObject<T> _instance;
    public static NamedObject<T> Instance {
        get {
            if (_instance == null) {
                _instance = new NamedObject<T>("Need to determine this string from the non-abstract child class of NamedObject");
            }
            return _instance;
        }
    }

    private string objectName;

    public NamedObject(string objectName) {
        this.objectName = objectName;
    }

    public string GetFullName() {
        return objectName + "(" + GetClassName() + ")";
    }

    protected virtual string GetClassName() {
        return typeof(T).ToString();
    }
}

Note that I need the generic T for GetClassName(), and note that to create an instance of the singleton, I need to call a static method of the child class that inherits this class (which seems to be impossible)

Edit: Updated the question to better reflect my problems.


Edit: Thanks for everyone's help. The solution for the second issue was to use a default constructor, and get the string that was supposed to be a parameter within the constructor from a non-static method of the child class (abstract in the base class).

In addition, my entire idea of Singleton inheritance was wrong, which I managed to fix thanks to Rob Lyndon's answer.

Here's the final code (I know it doesn't make sense, this is just a simplified version...):

public abstract class NamedObject<ME, T> where ME : NamedObject<ME, T>, new()
{
    private static NamedObject<ME, T> _instance;
    public static NamedObject<ME, T> Instance {
        get {
            if (_instance == null) {
                _instance = new ME();
            }
            return _instance;
        }
    }

    private string objectName = "test";

    public NamedObject() {
        this.objectName = GetObjectName();
    }

    public string GetFullName() {
        return objectName + "(" + GetClassName() + ")";
    }

    protected virtual string GetClassName() {
        return typeof(T).ToString();
    }

    protected abstract string GetObjectName();
}

And the child class:

public sealed class MyNamedObject : NamedObject<MyNamedObject, MyClass>
{
    public MyNamedObject() : base() {
    }

    protected override string GetObjectName () {
        return "MyName";
    }
}

So when calling MyNamedObject.Instance for the first time, it will NamedObject() constructor, with MyClass as T, and the objectName parameter will be "MyName" as defined by the child class MyNamedObject.

Exactly what I was looking for. Thanks for everyone's help this was very helpful.

Jon Skeet
people
quotationmark

I suggest you introduce an attribute which you decorate each type with, and extract that when you need to. You won't be able to validate at compile-time that the type has the right type, but there's not a lot you can do about that. Unit test all the types you'll need it for :)

[AttributeUsage(AttributeTargets.Class)]
public class NameAttribute : Attribute
{
    public NameAttribute(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }
}

[Name("Foo")]
public class SomeClass
{
}

Then in your singleton class, use a static constructor instead of having a thread-unsafe property.

private static readonly NamedObject<T> instance;

static NamedObject()
{
    // TODO: Validation :)
    var attributes = typeof(T).GetCustomAttributes(typeof(NameAttribute), false);
    var firstAttribute = ((NameAttribute[]) attributes)[0];
    string name = firstAttribute.Name;
    instance = new NamedObject<T>(name);
}

public static NamedObject<T> Instance { get { return instance; } }

Or use Lazy<> instead. See my article on singletons for more information on that side of things.

EDIT: To clarify - you shouldn't have NamedObject as an abstract class to start with. Singletons and inheritance simply don't mix. NamedObject<T> should be a sealed class instead, which has a single instance of any T. It doesn't enforce that there's only one instance of T created.

people

See more on this question at Stackoverflow