Inheritance with Singleton Pattern in C#

6

6tc1

Hi all, I'm looking to create a few singleton classes - they have
similar functionality and am wondering whether it is possible to safely
inherit the Singleton pattern from another class (not an interface)?

I've noticed in all "good" implementations of the Singleton pattern,
the classes are sealed - but I'm not entirely certain why this
restriction is place on Singleton classes. Is it possible to have a
base Singleton class with some base functionality and then safely
(thread related, etc) inherit from that base class.

The best theory I can come up with for "sealing" a Singleton class is
to prevent multiple instances of that base Singleton class from
existing (through multiple classes inheriting from it) - however, I
don't see why this poses a problem - since I would never actually want
an instance of this base class - just the classes that extend from it.

Thanks,
Novice
 
H

Helge Jensen

The best theory I can come up with for "sealing" a Singleton class is
to prevent multiple instances of that base Singleton class from
existing (through multiple classes inheriting from it) - however, I
don't see why this poses a problem - since I would never actually want
an instance of this base class - just the classes that extend from it.

Why would you want a singleton at all? why not just a canonical instance:

class WasSingleton {
... no limits on construction ...
public static WasSingleton Global = new WasSingleton(...);
}

Note that the singleton pattern specificly *not* discusses inheritance
since that breaks the promise of there only ever existing one instance
of the type. The GOF book variations of the singleton-pattern are plain
wierd, most of them are much better implemented by using a dictionary
(flywheel).

The singleton-pattern have two consequences:

1. canonical instance is available by syntax
2. prevents any other instance of type from existing

I hardly ever see anyone benefitting from 2, the only time I, myself,
have had benefit from preventing more than one instance was when
generating classes for introspection in c++: for each type, exactly one
instance of the introspection-type was allowed, to allow me to compare
introspected types by reference instead of value.
 
6

6tc1

Perhaps I have misunderstood your reply - but I'll try to be more clear
in what I need.

The architecture of the library I'm helping with requires the singleton
pattern. There are two separate types of Singletons that I need to
create. They both have similar internal functionality - but they both
also have some dissimilar functionality - so I was wondering if I could
create a base Singleton class like this:
public class Singleton
{
Singleton()
{
}

public static Singleton Instance
{
get
{
return Nested.instance;
}
}

class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}

internal static readonly Singleton instance = new Singleton();

void method1 (){
//some code
}

void method2 (){
//some code
}

}
}

class B : Singleton {
void method3 (){
//some code
}
void foo(){
//some code
}
}

class C : Singleton {
void method4 (){
//some code
}
void theSolution(){
//some code
}
}

I believe there could be a problem with the above - is that correct?

Thanks,
Novice
 
J

Joanna Carter [TeamB]

<[email protected]> a écrit dans le message de (e-mail address removed)...

| I've noticed in all "good" implementations of the Singleton pattern,
| the classes are sealed - but I'm not entirely certain why this
| restriction is place on Singleton classes. Is it possible to have a
| base Singleton class with some base functionality and then safely
| (thread related, etc) inherit from that base class.

If you think about it, a Singleton relies on keeping a single static
variable. If you inherit from this base class, then references to the
Singleton value of all the derived classes wil be the same instance which is
really an instance of the base class.

To avoid singleton instances sharing the same variable, you need a different
variable for each class. The code involved in doing the same thing for each
class is so minimal, inheritence really doesn't make any sense :)

If you want all your Singleton's to have the same behaviour, then you could
always add an aggregated object inside the singleton that implements the
commoin behaviour.

Joanna
 
6

6tc1

Essentially use containment instead of inheritance to capture the
common functionality?

Thanks,
Novice
 
J

Joanna Carter [TeamB]

<[email protected]> a écrit dans le message de (e-mail address removed)...

| Essentially use containment instead of inheritance to capture the
| common functionality?

I think that would be better :)

Joanna
 
H

Helge Jensen

Perhaps I have misunderstood your reply - but I'll try to be more clear
in what I need.

Perhaps I misunderstood the question, we will probably find out in the
discussion.
The architecture of the library I'm helping with requires the singleton
pattern. There are two separate types of Singletons that I need to
create. They both have similar internal functionality - but they both
also have some dissimilar functionality - so I was wondering if I could
create a base Singleton class like this:
public class Singleton

If there are two, they are not singletons ;) they are "canonical instances".

I took the liberty of formatting your code so it fits on less space:

class Singleton {
public static Singleton Instance { get { return Nested.instance; } }
class Nested {
static Nested() {} // Tell C# compiler not to beforefieldinit
internal static readonly Singleton instance = new Singleton();
void method1() { ...; }
void method2() { ...; }
}
}
class B: Singleton {
void method3() { ... }
void foo() { ...; }
}
class C: Singleton {
void method4() {}
void theSolution();
}

What i'm arguing is:

1. You probably don't single the "single" bit of the singleton pattern
(noone hardly ever does), the one stated as one half of "Intent" of the
pattern in the GOF book. If you ditch the single-instance constraint
there is less code to write. I name this pattern "canonical-instance".

2. "both have similar internal functionality - but they both also have
some dissimilar functionality" sounds like you need inheritance between
some Common class and the classes of your instances (like you
illustrate), not between some "Singleton" implementation and the classes
of your instances.

3. Why do you need to skip "beforefieldinit"?

Here is my proposed solution:

public class Common {
...
public void Method1() { ...; }
public void Method2() { ...; }
}
public class B: Common {
public static Global = new B();
public void Method3() { ...; }
void foo() { ...; }
}
public class C: Common {
public static Global = new C();
public void Method4() { ...; }
public void TheSolution() { ...; }
}

There are a few notes to this:

a. Anyone is free to implement their own Common, B or C, ... for
example a debug edition, and change B/C.Global to that, it's rather
handy -- as opposed to the "Singleton"-pattern.

b. You can limit editing of Global by making it a property, of course
you will then need a (protected or private) instance that the Global
property can update.

c. There are no static constructors, why should static instances be
created before they are used?

If it's a case of one depending upon the other (or others depending
upon them) make Global a Property, so you get deterministic invocation
of the static constructions. search for "static initialization order
fiasco", or see for example
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12, it's c++ but
it's just the same in C#, except you can use a property instead of a
function).

Example of all of the above:

// C.cs:
public class C: Common {
protected static C global;
public static Global {
get {
lock ( typeof(C) ) {
if ( global == null ) {
... lots of activity ..
global = x;
}
}
return global;
}
set {
lock ( typeof(C) ) {
if ( check_if_valid() )
global = value;
else
throw new InvalidOperation(
string.Format("{0}.Global= not allowed: {1}",
GetType(), reason));
}
}
public virtual void F() { ...; }
}

// MyApp.cs:
class CDebug: C {
public override void F() {
Console.WriteLine("F called");
base.F();
}
}

if ( in_debug_mode )
C.Global = new CDebug();
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top