Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this questionI need to store a bunch of variables that need to be accessed globally and I'm wondering if a singleton pattern would be applicable. From the examples I've seen, a singleton pattern is just a static class that can't be inherited. But the examples I've seen are overly complex for my needs. What would be the very simplest singleton class? Couldn't I just make a static, sealed class with some variables inside?
Typically a singleton isn't a static class - a singleton will give you a single instance of a class.
I don't know what examples you've seen, but usually the singleton pattern can be really simple in C#:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
static Singleton() {} // Make sure it's truly lazy
private Singleton() {} // Prevent instantiation outside
public static Singleton Instance { get { return instance; } }
}
That's not difficult.
The advantage of a singleton over static members is that the class can implement interfaces etc. Sometimes that's useful - but other times, static members would indeed do just as well. Additionally, it's usually easier to move from a singleton to a non-singleton later, e.g. passing in the singleton as a "configuration" object to dependency classes, rather than those dependency classes making direct static calls.
Personally I'd try to avoid using singletons where possible - they make testing harder, apart from anything else. They can occasionally be useful though.
There are several Patterns which might be appropriate for you, a singleton is one of the worse.
Registry
struct Data {
public String ProgramName;
public String Parameters;
}
class FooRegistry {
private static Dictionary<String, Data> registry = new Dictionary<String, Data>();
public static void Register(String key, Data data) {
FooRegistry.registry[key] = data;
}
public static void Get(String key) {
// Omitted: Check if key exists
return FooRegistry.registry[key];
}
}
Advantages
- Easy to switch to a Mock Object for automated testing
- You can still store multiple instances but if necessary you have only one instance.
Disadvantages
- Slightly slower than a Singleton or a global Variable
Static Class
class GlobalStuff {
public static String ProgramName {get;set;}
public static String Parameters {get;set;}
private GlobalStuff() {}
}
Advantages
- Simple
- Fast
Disadvantages
- Hard to switch dynamically to i.e. a Mock Object
- Hard to switch to another object type if requirements change
Simple Singleton
class DataSingleton {
private static DataSingleton instance = null;
private DataSingleton() {}
public static DataSingleton Instance {
get {
if (DataSingleton.instance == null) DataSingleton.instance = new DataSingleton();
return DataSingleton;
}
}
}
Advantages
- None really
Disadvantages
- Hard to create a threadsafe singleton, the above Version will fail if multiple threads access the instance.
- Hard to switch for a mock object
Personally I like the Registry Pattern but YMMV.
You should take a look at Dependency Injection as it's usually considered the best practice but it's too big a topic to explain here:
Dependency Injection
A Singleton isn't just a static class that can't be inherited. It's a regular class that can be instantiated only once, with everybody sharing that single instance (and making it thread safe is even more work).
The typical .NET code for a Singleton looks something like the following. This is a quick example, and not by any means the best implementation or thread-safe code:
public sealed class Singleton
{
Singleton _instance = null;
public Singleton Instance
{
get
{
if(_instance == null)
_instance = new Singleton();
return _instance;
}
}
// Default private constructor so only we can instanctiate
private Singleton() { }
// Default private static constructor
private static Singleton() { }
}
If you're going to go down the path you're thinking, a static sealed class will work just fine.
Using C# 6 Auto-Property Initializers.
public sealed class Singleton
{
private Singleton() { }
public static Singleton Instance { get; } = new Singleton();
}
Short and clean - I'll be happy to hear the downsides.
I know this Issue is old, but here is another solution using .Net 4.0 or later (including .Net Core and .Net Standard).
First, define your class that will be transformed into a Singleton:
public class ClassThatWillBeASingleton
{
private ClassThatWillBeASingleton()
{
Thread.Sleep(20);
guid = Guid.NewGuid();
Thread.Sleep(20);
}
public Guid guid { get; set; }
}
In this Example Class I've defined one constructor that Sleeps for a while, and then creates one new Guid and save to it's public property. (The Sleep is just for concurrency testing)
Notice that the constructor is private, so that no one can create a new instance of this class.
Now, We need to define the wrapper that will transform this class into a singleton:
public abstract class SingletonBase<T> where T : class
{
private static readonly Lazy<T> _Lazy = new Lazy<T>(() =>
{
// Get non-public constructors for T.
var ctors = typeof(T).GetConstructors(System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
if (!Array.Exists(ctors, (ci) => ci.GetParameters().Length == 0))
throw new InvalidOperationException("Non-public ctor() was not found.");
var ctor = Array.Find(ctors, (ci) => ci.GetParameters().Length == 0);
// Invoke constructor and return resulting object.
return ctor.Invoke(new object[] { }) as T;
}, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
public static T Instance
{
get { return _Lazy.Value; }
}
}
Notice that it uses Lazy to create a field _Lazy
that knows how to instantiate a class using it's private constructor.
And it defines one Property Instance
to access the Value of the Lazy field.
Notice the LazyThreadSafetyMode
enum that is passed to the Lazy constructor. It is using ExecutionAndPublication
. So only one thread will be allowed to initialize the Value of the Lazy field.
Now, all we have to do is define the wrapped class that will be a singleton:
public class ExampleSingleton : SingletonBase<ClassThatWillBeASingleton>
{
private ExampleSingleton () { }
}
Here is one example of the usage:
ExampleSingleton.Instance.guid;
And one test to assert that two threads will get the same instance of the Singleton:
[Fact()]
public void Instance_ParallelGuid_ExpectedReturnSameGuid()
{
Guid firstGuid = Guid.Empty;
Guid secondGuid = Guid.NewGuid();
Parallel.Invoke(() =>
{
firstGuid = Singleton4Tests.Instance.guid;
}, () =>
{
secondGuid = Singleton4Tests.Instance.guid;
});
Assert.Equal(firstGuid, secondGuid);
}
This test is calling the Value of the Lazy field concurrently, and we want to assert that both instances that will be returned from this property (Value of Lazy) are the same.
More details about this subject can be found at: C# in Depth
So, as far as I am concerned, this is the most concise and simple implementation of the Singleton pattern in C#.
http://blueonionsoftware.com/blog.aspx?p=c6e72c38-2839-4696-990a-3fbf9b2b0ba4
I would, however, suggest that singletons are really ugly patterns... I consider them to be an anti-pattern.
http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx
For me, I prefer to have something like a Repository, implementing IRepository. Your class can declare the dependency to IRepository in the constructor and it can be passed in using Dependency Injection or one of these methods:
http://houseofbilz.com/archive/2009/05/02.aspx
Use your language features. Mostly simple thread-safe implementation is:
public sealed class Singleton
{
private static readonly Singleton _instance;
private Singleton() { }
static Singleton()
{
_instance = new Singleton();
}
public static Singleton Instance
{
get { return _instance; }
}
}
...what would be the very simplest singleton class?
Just to add one more possible solution. The simplest, most straight forward and easy to use approach I can think of would be something like this:
//The abstract singleton
public abstract class Singleton<T> where T : class
{
private static readonly Lazy<T> instance = new Lazy<T>( CreateInstance, true );
public static T Instance => instance.Value;
private static T CreateInstance()
{
return (T)Activator.CreateInstance( typeof(T), true);
}
}
//This is the usage for any class, that should be a singleton
public class MyClass : Singleton<MyClass>
{
private MyClass()
{
//Code...
}
//Code...
}
//Example usage of the Singleton
class Program
{
static void Main(string[] args)
{
MyClass clazz = MyClass.Instance;
}
}
精彩评论