views:

755

answers:

7

As an exercise, I'm translating parts of our large and battle-hardened Delphi-framework to C#.

Included in this framework is a generic singleton parent class. Of course, implementing a singleton in C# is fairly easy (there is even a Jon Skeet article, so what more could I wish for), but our Delphi singleton has a slightly different take on the pattern: as opposed to publishing an 'instance' property/method, it has a "fake" constructor that always returns the same instance. The essential characteristic of this approach is that the user of the singleton class doesn't know that he is dealing with a singleton: as far as they know, they just construct any old class and request some information from it.

I want to accomplish the same thing in C# (as an exercise, so it doesn't have to be production-quality code, evil hackery is fine), but so far I've failed.

Any suggestion to make a simple myInstance = new MyClass(); always return the same instance is most welcome!


Additional info

  • We are talking a convenience-implementation of the singleton pattern, as offered by the framework. It doesn't necessarely have to be a parent-class, but it does have to assist the developers in creating their own singletons as well. Requiring them to manually redirect all their method calls to the single-instance will not make them overflow with joy. :-)

  • I'm not really interested in debating whether or not this is the right way to deal with singletons, for now I'm just interested in the finer art of c#-tweaking.

A: 

I don't see how you can, as constructors don't use a return statement. You could clone all of the relevant links to the singleton, but it would have local copies of local variables, and be very messy.

Instead have the constructor check if the singleton is instantiated, and if it has been already, throw an exception, or log a warning to the developer who is using the old style code.

Karl
Yeah, that would be the sane route (I assume by compile-time exceptions you mean #error directives?). However, I'm interested in your statement about cloning relevant links... I was currently investigating a smart overloaded implicit conversion operator.
Paul-Jan
There are no instances at compile time--what are you talking about?
chaiguy
Yeah I wasnt writing clearly when I said 'compile time exception' I guess an IDE warning would be better, or some simple logging or console statement warning.
Karl
A: 

I think you could possibly roll something with Remoting.

Update:

A better way would be to wrap a proper singleton class in a struct or lightweight class.

leppie
+2  A: 

As far as I know, this cannot be done for real because of how C# handles object instances. In order for a constructor to be called, the instance has to actually be created, and you can't just "return" another object from a constructor.

The best thing I can come up with (other than using a factory method) is to treat the class internally as a Singleton, and create "dummy" instances that all just point back to that original instance, when created. So for example, in your constructor you would check to see if the singleton has been initialized, and if not, would initialize it, then you would basically just proxy each instance's methods and properties back to the singleton.

In this implementation, the singleton needn't even be necessarily the same class, but you could if you wanted to keep things contained.

Update: One drawback of this approach is that although each instance would behave as a singleton, it would still have its own object reference and therefore you might also want to override Equals() for equality comparisons.

chaiguy
Good solution to the reference equality thing. As I noted in my post my1 != my2 with the solution, but this could be solved with an equals override. object.ReferenceEquals would still return false, but you shouldn't be doing that anyways.
George Mauer
This sounds like a great idea... but now I want to offer this pattern from our framework so developers can conveniently derive their own singletons as well. Requiring them to manually proxying all their methods is error-prone, perhaps we can think of a way to do this automatically?
Paul-Jan
You can try playing around with Castle project's DynaProxy library, I think it would allow you to implement this pattern automatically. However, you don't want to be using this pattern at all! The point where you're doing all this automagic under the sheets might be where to draw the line.
George Mauer
@Paul: That's a tricky question, and one I've thought about in the past. Off the top of my head, you might be able to do something with reflection, but even if you could get it to work (which I doubt--since how do you expose the right methods?) it would be slow. Maybe dynamics in C# 4.0??
chaiguy
+7  A: 

You would do a Proxy (Edit: As Tom points out below, the proper design pattern is Monostate):

public class MyClass {
  MyActualClass _actual;
  public MyClass() {
    _actual = MyActualClass. Instance;
  }
  public DoStuff() {
    _actual.DoStuff();
  }
}

internal class MyActualClass {
  private MyActualClass {
  }
  public DoStuff() {
    ...
  }
  MyActualClass _instance;
  public static Instance {
    get {
       if(_instance == null)
         _instance = new MyActualClass()
       return _instance;
    }
  }
}

....

public static void Main() {
  var my1 = new MyClass();
  var my2 = new MyClass();   
}

my1 != my2 but my1.DoStuff() calls the same instance of the method as my2.DoStuff() This would be simplified even further if you programmed of an interface only.

Edit: The equality problem could partially be solved by making _actual protected internal and overwriting MyClass.Equals(object obj) to check whether this._actual == obj._actual

George Mauer
This is exactly what I meant. Thanks for illustrating it. :) Good to know I think in patterns without even realizing it, lol.
chaiguy
This looks like the closest you can get to it.
Kaius
I agree, this is the only way I can see this working as using the new keyword doesn't actually return anything. Is this not the case with delphi?
Owen
A: 

Create the singleton as a static member and make all methods access the single static instance.

class SingletonWrapper {

    private static RealSingleton instance = new RealSingleton();

    public void methodA() {
        instance.methodA();
    }

    public String getA() {
        return instance.getA();
    }

}

(This is actually Java code but C# is similar enough, I think. :)

Bombe
you can't new use new with a static constructor. Static constructors only get called when the first static method is referenced.
George Mauer
@Bombe: That would work. It would however be very hard to maintain such a singleton, not exactly a convenient parent-class to provide in the framework.@George: I don't think that's the point. New() simply calls the default constructor, but any method accesses the same static instance
Paul-Jan
Oh I see, yes I see now
George Mauer
Wouldn't that create a stack overflow (lol) though? instance.methodA() would just invoke instance.methodA() again and so on...
chaiguy
chaiguy1337: Oops. Yes, it would. Paul-Jan: Indeed, as a parent class it would mostly suck. In general it’s hard to have some kind of framework for singletons because the concepts just don’t mix. :)
Bombe
+4  A: 

I believe the Monostate pattern will give you what you need:

"The Monostate gives us the singularity of state that we so treasure in the Singleton, but without all of the static headaches that come along with it."

More here: http://jeremyjarrell.com/archive/2008/04/21/88.aspx

Tom
I think that's what we've been discussing--just didn't know the name of it.
chaiguy
Yup, thanks for pointing out the name, I hadn't previously heard the term. But yes, that is exactly what I was talking about
George Mauer
A: 

How about using a static function to return an object insted of using the new keyword.

static private m_obj my_obj;
static private bool my_new_obj;
static public m_obj create_m_obj()
{
    if (my_new_obj == false)
    {
        my_new_obj = true;
        my_obj = new my_obj();
    }
    return my_obj;
}

Then you have easy full controle over the creation of the object, if I an not mistaken.

eaanon01