1

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.

tbkn23
  • 5,205
  • 8
  • 26
  • 46
  • what are you trying to do here? abstract generic singleton huh? You can't create new NamedObject, it's abstract. WHat does abstract singleton mean? – Erti-Chris Eelmaa Nov 15 '13 at 22:06
  • Right... Another thing I got wrong :). My goal is to have a parent class, and all the child classes will be singletons without having to re-write the singletone code per child class. – tbkn23 Nov 15 '13 at 22:09
  • Obligatory [singletons are bad link](http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons). – Mike Nov 15 '13 at 22:16
  • @Mike I'm aware of the pros and cons of singletons. They have their uses. In my case I use them to load resources, which is an acceptable use. http://c2.com/cgi/wiki?SingletonsAreGood – tbkn23 Nov 15 '13 at 22:22

3 Answers3

2

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I didn't know about static constructors, but it seems to do exactly what I need to do (without the decorations, which I don't quite understand... I'm more of a c++ person most of the time). I'll check it out and let you know. Thanks. – tbkn23 Nov 15 '13 at 22:11
  • @tbkn23: The static constructor doesn't really solve the problem of where to get the name from - that's a matter of applying the idea of *attributes*, which I suggest you read up on here: http://msdn.microsoft.com/en-us/library/z0w1kczw(v=vs.110).aspx The static constructor just sorts out thread safety. – Jon Skeet Nov 15 '13 at 22:13
  • Hmm... actually I think static constructor might not help because the child classes do not inherit it... Is there any way whatsoever to make have a base singleton class and have every inherited class automatically get the singleton functionality without rewriting the code? I'll read up your link, thanks. – tbkn23 Nov 15 '13 at 22:14
  • @tbkn23: See my edit. Basically, don't try to use singletons with inheritance itself. It simply doesn't work. If you need an instance of `T` as well, that's a different matter - basically you'd need to specify your requirements in more detail. I'd also try to avoid singletons in the first place if possible, but that's a slightly different matter. – Jon Skeet Nov 15 '13 at 22:17
  • I get it. Well, I was hoping to have a simpler solution but the main problem is that statics are not inherited... Thanks. – tbkn23 Nov 15 '13 at 22:24
2

Don't do singletons. Ever.

Anyway, here is one way of doing them that comes close to your use case.

// base class
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 { objectName = GetLabel(typeof(T)) };
            }
            return _instance;
        }
    }

    private string objectName;

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

    protected abstract string GetLabel(Type type);
    protected abstract string GetClassName();
}
tbkn23
  • 5,205
  • 8
  • 26
  • 46
Rob Lyndon
  • 12,089
  • 5
  • 49
  • 74
  • Ok, this worked for me, but a few small changes: I needed my original T, which was replaced with the child class in your script. Instead, I used `NamedObject where ME : NamedObject, new()`. The only place where T is used is in the `typeof`, all the rest are ME. Second, I didn't really need the `typeof` value, I needed a string that is determined by the type, but not the type itself. The solution I found eventually was to use an empty constructor, and within the constructor itself I called an abstract method. Please update answer with the first part at least and I can accept it. – tbkn23 Nov 15 '13 at 23:06
  • Done. Hope it goes well for you. – Rob Lyndon Nov 15 '13 at 23:13
0

This should do what you want (the Name property could also be an abstract method, seems better as a property if we're going with the singleton pattern).

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(MyNamedObject.Instance.Name);
    }
}

public abstract class NamedObject<T> where T : NamedObject<T>, new()
{
    private static T _instance;

    public abstract string Name { get; }

    public static T Instance
    {
        get { return _instance ?? (_instance = new T()); }
    }
}

public class MyNamedObject : NamedObject<MyNamedObject>
{
    public override string Name
    {
        get { return "My Named Object Name"; }
    }
}
Mike
  • 1,837
  • 10
  • 9