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();