views:

1858

answers:

5

I want to create a static class or singleton class that accepts a reference to another object in its constructor. Static classes are out, but I figured I could create a singleton that accepts parameters in its constructor. So far I haven't had any luck figuring out or googling the syntax. Is this possible? if so, how do I do it?

Sorry for no example in the initial post, I wrote it in a rush. I have the feeling that my answer is already in the replies, but here's some clarification of what I want to do:

I want to create a single instance of a specific type (said Singleton), but that single instance of the type needs to hold a reference to a different object.

For example, I might want to create a Singleton "Status" class, which owns a StringBuilder object and a Draw() method that can be called to write said StringBuilder to the screen. The Draw() method needs to know about my GraphcisDevice in order to draw. So what I want to do it this:

public class Status
{
private static Status _instance;
private StringBuilder _messages;
private GraphicsDevice _gDevice;

private Status(string message, GraphicsDevice device)
{
    _messages.Append(message);
    _gDevice = device;
}

// The following isn't thread-safe

// This constructor part is what I'm trying to figure out
public static Status Instance // (GraphicsDevice device) 
    {
    get
        {
        if (_instance == null)
            {
            _instance = new Status("Test Message!", device); 
            }
        return _instance;
        }
    }

public void UpdateMessage
...

public void Draw()
    {
    // Draw my status to the screen, using _gDevice and _messages
    }
}

All over the code, I retrieve my Status Singleton and call its UpdateMessage() method.

private Status _status = Status.Instance; // + pass reference to GraphicsDevice
_status.UpdateMessage("Foo!");

Then, in my main class I also retrieve the singleton, and draw it:

_status.Draw();

Yes, this means that wherever I retrieve the singleton, I need to do so by passing in the reference to the GraphicsDevice, in case it's the first time I instantiate the Singleton. And I could/would use different means to retrieve something as fundamental as the GraphicsDevice in my Singleton class, for example register a service elsewhere and get that service in the Status class. This example got pretty contrived - I'm trying to figure out if something like this pattern is possible in the first place.

+1  A: 

What you are describing is a Generic Singleton. It looks like this:

public class SingletonProvider <T> where T:new()
{
    SingletonProvider() {}

    public static T Instance
    {
        get { return SingletonCreator.instance; }
    }

    class SingletonCreator
    {
        static SingletonCreator() { }

        internal static readonly T instance = new T();
    }
}

http://www.codeproject.com/KB/cs/genericsingleton.aspx

Robert Harvey
How can you guarantee that there aren't any other instances of type T in your application? This isn't really a singleton.
Andrew Hare
I assume that the person asking the question already understands that he cannot use the type for anything else. He asked for the knife, I didn't tell him what to do with it.
Robert Harvey
+2  A: 

This is generally considered a bad idea because if you are going to accept either an object reference or a type argument that you plan on wrapping in a singleton-like wrapper you cannot guarantee that you hold the only instance of that type in the AppDomain.

The whole point of the singleton pattern is to control a single instance of a type so that only one instance of that type can exist. If you allow an instance to be passed in or if you make a generic singleton provider you cannot guarantee that your instance is the only instance.

Let's say that I had a SingletonFactory<T> that would allow me to create a singleton around any type that I pass to the factory. That would be quite handy and would allow me to do something like this:

SingletonFactory<Foo>.Instance;

But what stops me from also doing this:

Foo foo = new Foo();

Oops, it looks like Foo isn't a singleton anymore as I can create as many instances of it as I wish. In order for the singleton pattern to work you need to be able to completely control the type whose instances you need to restrict. This is why you ought not to use anything like my SingletonFactory<T>.

Note: The same goes for a non-generic singleton that accepts an object instance. I am sure that you can extrapolate from my previous example many similar reasons why a singleton wrapper that accepts and object reference would also be a bad idea.

Andrew Hare
A: 

What you're specifically asking for looks like this, I think:

public sealed class Singleton {
    static Singleton instance = null;
    static readonly object padlock = new Object();

    Singleton(Object o) {
    }

    public static Singleton Instance(Object o) {
        lock (padlock) {
            if (instance == null) {
                instance = new Singleton(o);
            }
            return instance;
        }
    }
}

Singleton s = Singleton.Instance(new Object());

I suspect that the generic version already posted is what you really want, though.

Tim Sylvester
+1  A: 

You need a private constructor and then a getInstance method, this method is who should receive the param, the constructor must be private and it can have params also, but getInstance should pass it, no you. Btw, what you're doing? Some real example could help.

Alaor
A: 

One thing you can do may be sticking to the singleton sample you found and just exposing a property (setter, if needed, add getter as well) and use it like MySingleton.Instance.MyReference = new MyObject();

If you have to restrict the usage of your singleton object, for example, any operations on the singleton object before the reference is set need to be illegal, you can have a private boolean flag, for example, hasBeenIntialized and MyReference setter will set the flag internally. All other methods will check the flag at the beginning of the execution and throw an exception if any method is called if hasBeenInitialized is false.

If you need to have a readonly behavior, you may throw an exception in MyReference setter if anyone wants to assign a different object while hasBeenInitialized is set to true.

Chansik Im