views:

188

answers:

3

I have a base class that has a private static member:

class Base
{
    private static Base m_instance = new Base();
    public static Base Instance
    {
        get { return m_instance; }
    }
}

And I want to derive multiple classes from this:

class DerivedA : Base {}
class DerivedB : Base {}
class DerivedC : Base {}

However, at this point calling DerivedA::Instance will return the same exact object as will DerivedB::Instance and DerivedC::Instance. I can solve this by declaring the instance in the derived class, but then every single derived class will need to do that and that just seems like it should be unneccessary. So is there any way to put all this in the base class? Could a design pattern be applied?

+6  A: 

Static methods does not support polymorphism, therefore, such a thing is not possible.

Fundamentally, the Instance property has no idea how you're using it. And a single implementation of it will exist, as it's static. If you really wanted to do this, this "not recommended" solution is available (I got the idea from Jon's solution):

private static Dictionary<Type, Base> instances = new Dictionary<Type, Base>();
public static T GetInstance<T>() where T : Base, new() {
  Type ty = typeof(T);
  T x;
  if (instances.TryGetValue(ty, out x)) return x;
  x = new T();
  instances[ty] = x;
  return x;
}
Mehrdad Afshari
+10  A: 

There's one really icky way of doing this:

class Base
{
     // Put common stuff in here...
}

class Base<T> : Base where T : Base<T>, new()
{
    private static T m_instance = new T();

    public static T Instance { get { return m_instance; } }
}

class DerivedA : Base<DerivedA> {}
class DerivedB : Base<DerivedB> {}
class DerivedC : Base<DerivedC> {}

This works because there's one static variable per constructed type - e.g. List<string> is a different type to List<int> and so would have separate static variables.

I've taken the opportunity of making it an instance of the derived class as well - I don't know whether that's what you want or not, but I thought I'd at least make it available for you :)

In general though, this is a nasty thing to do. Static variables aren't really designed for this kind of use - I've just abused a feature of generics to get "sort of" the behaviour you asked for.

Also note that Base<DerivedA>.Instance will return the same result as DerivedA.Instance - the property/variable don't "know" that you're using DerivedA.Instance. I don't know whether or not that's important to you.

With the extra non-generic class, you can write:

Base t = DerivedA.Instance;
t = DerivedB.Instance;

If you don't need that, take it out :)

Jon Skeet
LOL, someone downvoted you, that's a first for me to see! :)
leppie
This will cause fundamental problems, as Base<DerivedA> is different from Base<DerivedB>. You should derive them from the same base class.
Mehrdad Afshari
Oh I get plenty of downvotes. Rarely an explanation though :( The annoying thing is that at this point in the day, even if this answer is upvoted 20 times, I'll still have a net reputation of -2 from it due to the cap (unless it's accepted, of course).
Jon Skeet
@Mehrdad: We don't know whether it will cause a problem or not. The OP hasn't said what he wants to use this for. I'm aware that they're different types - that's why it works in the first place. It *may* do exactly what the OP wants (although it's still not a nice solution.)
Jon Skeet
Yeah I know you said it's an icky solution. But I just wanted to note if you use this method, you'll not be able to do "Base x = DerivedA.Instance;" which might be necessary.
Mehrdad Afshari
Edited answer to allow that :)
Jon Skeet
It's so awkward - he's creating singletons which aren't. This reeks of refactor so much I think JS (and everyone) should be allowed leeway in their response so long as it's made clear this is Not Good.
annakata
"Patient: Doctor, my arm hurts when I do this. Doctor: Then don't do that." Dude, I'm not sure what you're trying to achieve, but I'll bet $1,000,000 theres a better way of doing it. +1 to James. You don't want to do this Mike trust me.
Binary Worrier
I don't really see what is "icky" in the solution you gave, it's a nice application of the Curiously Recurring Template Pattern. But well, maybe it's my C++ conception of life that makes me see that as perfectly clear and logical :-)!
Luc Touraille
@Luc: As annakata said, it's a "not quite singleton". There's nothing to stop any other classes from creating instances of DerivedA, DerivedB etc - or deriving from Base<DerivedA> themselves. It's a workaround rather than a real solution.
Jon Skeet
Yes, I know this isn't a good thing, that's why I asked for a design pattern or alternate way to do this. And yes, it basically is a singleton but I'm just trying to find a way to keep all the singleton code in the base class so that the derived classes don't need to reinvent the wheel each time.
Mike Hall
+3  A: 

Short answer: not that I'm aware of. Static members are always nonvirtual and do not readily support polymorphism.

However, you should also ask yourself why you are doing this. Normally, static members are shared resources that every instance of that class (including the derived classes) will find useful. However, when you make a static instance, you are usually building towards a singleton pattern. In this case, you usually want to seal the class so you can't have derived classes, thus rendering the entire point moot. Thus, you should really be analyzing why you are wanting to do this and solve that problem instead.

James