C# 通用单例<T>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2319075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generic Singleton<T>
提问by MRFerocius
I have a question, is this the correct approach to make a Generic Singleton?
我有一个问题,这是制作通用单例的正确方法吗?
public class Singleton<T> where T : class, new()
{
private static T instance = null;
private Singleton() { }
public static T Instancia
{
get
{
if (instance == null)
instance = new T();
return instance;
}
}
}
EDIT:
编辑:
Checking some PDFs I found a generic Singleton made this other way, is this other correct?
检查一些 PDF 我发现一个通用的单例是用其他方式制作的,这个正确吗?
public class Singleton<T> where T : class, new()
{
Singleton() { }
class SingletonCreator
{
static SingletonCreator() { }
// Private object instantiated with private constructor
internal static readonly T instance = new T();
}
public static T UniqueInstance
{
get { return SingletonCreator.instance; }
}
}
采纳答案by Andrew Hare
The problem with a generic singleton factory is that since it is generic you do not control the "singleton" type that is instantiated so you can never guarantee that the instance you create will be the only instance in the application.
通用单例工厂的问题在于,由于它是通用的,因此您无法控制实例化的“单例”类型,因此您永远无法保证您创建的实例将是应用程序中的唯一实例。
If a user can provide a type to as a generic type argument then they can also create instances of that type. In other words, you cannot create a generic singleton factory - it undermines the pattern itself.
如果用户可以提供一个类型作为泛型类型参数,那么他们也可以创建该类型的实例。换句话说,你不能创建一个通用的单例工厂——它破坏了模式本身。
回答by xyz
For a generic piece of code that will be reused, you should consider thread safety at the point where you create the singleton instance.
对于将被重用的通用代码段,您应该在创建单例实例时考虑线程安全性。
As it is, (instance == null)
couldevaluate to true on separate threads.
事实上,(instance == null)
可以在单独的线程上评估为真。
回答by Alexandr
this is my point using .NET 4
这是我使用 .NET 4 的观点
public class Singleton<T> where T : class, new()
{
private Singleton (){}
private static readonly Lazy<T> instance = new Lazy<T>(()=> new T());
public static T Instance { get { return instance.Value; } }
}
Usage pattern:
使用模式:
var journalSingleton = Singleton<JournalClass>.Instance;
回答by Chris Shepley
Here is my implementation using a non-public constructor. The only issue right now is there is no way to have a custom constraint on C# generics, so I have to throw a run-time exception for derived classes with public default constructors instead of a compile-time error.
这是我使用非公共构造函数的实现。现在唯一的问题是无法对 C# 泛型设置自定义约束,因此我必须为具有公共默认构造函数的派生类抛出运行时异常,而不是编译时错误。
using System;
using System.Reflection;
using System.Threading;
/// <summary>
/// A generic abstract implementation of the Singleton design pattern (http://en.wikipedia.org/wiki/Singleton_pattern).
///
/// Derived type must contain a non-public default constructor to satisfy the rules of the Singleton Pattern.
/// If no matching constructor is found, an exception will be thrown at run-time. I am working on a StyleCop
/// constraint that will throw a compile-time error in the future.
///
/// Example Usage (C#):
///
/// class MySingleton : Singleton<MySingleton>
/// {
/// private const string HelloWorldMessage = "Hello World - from MySingleton";
///
/// public string HelloWorld { get; private set; }
///
/// // Note: *** Private Constructor ***
/// private MySingleton()
/// {
/// // Set default message here.
/// HelloWorld = HelloWorldMessage;
/// }
/// }
///
/// class Program
/// {
/// static void Main()
/// {
/// var mySingleton = MySingleton.Instance;
/// Console.WriteLine(mySingleton.HelloWorld);
/// Console.ReadKey();
/// }
/// }
/// </summary>
/// <typeparam name="T">Type of derived Singleton object (i.e. class MySingletone: Singleton<MySingleton>).</typeparam>
public abstract class Singleton<T> where T : class
{
/// <summary>
/// "_instance" is the meat of the Singleton<T> base-class, as it both holds the instance
/// pointer and the reflection based factory class used by Lazy<T> for instantiation.
///
/// Lazy<T>.ctor(Func<T> valueFactory,LazyThreadSafetyMode mode), valueFactory:
///
/// Due to the fact Lazy<T> cannot access a singleton's (non-public) default constructor and
/// there is no "non-public default constructor required" constraint available for C#
/// generic types, Lazy<T>'s valueFactory Lambda uses reflection to create the instance.
///
/// Lazy<T>.ctor(Func<T> valueFactory,LazyThreadSafetyMode mode), mode:
///
/// Explanation of selected mode (ExecutionAndPublication) is from MSDN.
///
/// Locks are used to ensure that only a single thread can initialize a Lazy<T> instance
/// in a thread-safe manner. If the initialization method (or the default constructor, if
/// there is no initialization method) uses locks internally, deadlocks can occur. If you
/// use a Lazy<T> constructor that specifies an initialization method (valueFactory parameter),
/// and if that initialization method throws an exception (or fails to handle an exception) the
/// first time you call the Lazy<T>.Value property, then the exception is cached and thrown
/// again on subsequent calls to the Lazy<T>.Value property. If you use a Lazy<T>
/// constructor that does not specify an initialization method, exceptions that are thrown by
/// the default constructor for T are not cached. In that case, a subsequent call to the
/// Lazy<T>.Value property might successfully initialize the Lazy<T> instance. If the
/// initialization method recursively accesses the Value property of the Lazy<T> instance,
/// an InvalidOperationException is thrown.
///
/// </summary>
private static readonly Lazy<T> _instance = new Lazy<T>(() =>
{
// Get non-public constructors for T.
var ctors = typeof (T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
// If we can't find the right type of construcor, throw an exception.
if (!Array.Exists(ctors, (ci) => ci.GetParameters().Length == 0))
{
throw new ConstructorNotFoundException("Non-public ctor() note found.");
}
// Get reference to default non-public constructor.
var ctor = Array.Find(ctors, (ci) => ci.GetParameters().Length == 0);
// Invoke constructor and return resulting object.
return ctor.Invoke(new object[] {}) as T;
}, LazyThreadSafetyMode.ExecutionAndPublication);
/// <summary>
/// Singleton instance access property.
/// </summary>
public static T Instance
{
get { return _instance.Value; }
}
}
/// <summary>
/// Exception thrown by Singleton<T> when derived type does not contain a non-public default constructor.
/// </summary>
public class ConstructorNotFoundException : Exception
{
private const string ConstructorNotFoundMessage = "Singleton<T> derived types require a non-public default constructor.";
public ConstructorNotFoundException() : base(ConstructorNotFoundMessage) { }
public ConstructorNotFoundException(string auxMessage) : base(String.Format("{0} - {1}", ConstructorNotFoundMessage, auxMessage)) { }
public ConstructorNotFoundException(string auxMessage, Exception inner) : base(String.Format("{0} - {1}", ConstructorNotFoundMessage, auxMessage), inner) { }
}
回答by Ehsan Shirvan
for creating generic Singleton factory you can use something like this class as your factory :
要创建通用的单例工厂,您可以使用此类作为您的工厂:
public abstract class BaseLazySingleton<T> where T : class
{
private static readonly Lazy<T> LazyInstance =
new Lazy<T>(CreateInstanceOfT, LazyThreadSafetyMode.ExecutionAndPublication);
#region Properties
public static T Instance
{
get { return LazyInstance.Value; }
}
#endregion
#region Methods
private static T CreateInstanceOfT()
{
return Activator.CreateInstance(typeof(T), true) as T;
}
protected BaseLazySingleton()
{
}
#endregion
}
Note that
注意
- this generator is abstract so no one can create new Instance of this class.
- constructor method is protected Not public
- 这个生成器是抽象的,所以没有人可以创建这个类的新实例。
- 构造函数方法受保护 不公开
回答by MaurGi
This how I did it, using the Current pattern (also thread safe initialization)
这是我如何做到的,使用当前模式(也是线程安全初始化)
public static class Singleton<T>
{
private static readonly object Sync = new object();
public static T GetSingleton(ref T singletonMember, Func<T> initializer)
{
if (singletonMember == null)
{
lock (Sync)
{
if (singletonMember == null)
singletonMember = initializer();
}
}
return singletonMember;
}
}
Usage:
用法:
private static MyType _current;
public static MyType Current = Singleton<MyType>.GetSingleton(ref _current, () => new MyType());
Consume the singleton:
使用单例:
MyType.Current. ...
回答by Wesley
You can make a singleton base class using a bit of cheating (reflection). You can (run-time) enforce a class has no public constructor.
您可以使用一些作弊(反射)来制作单例基类。您可以(运行时)强制一个类没有公共构造函数。
public abstract class Singleton<T> where T : Singleton<T> {
private const string ErrorMessage = " must have a parameterless constructor and all constructors have to be NonPublic.";
private static T instance = null;
public static T Instance => instance ?? (instance = Create());
protected Singleton() {
//check for public constructors
var pconstr = typeof(T).GetConstructors(BindingFlags.Public | BindingFlags.Instance);
//tell programmer to fix his stuff
if (pconstr.Any())
throw new Exception(typeof(T) + ErrorMessage);
}
private static T Create() {
try {
//get nonpublic constructors
var constructors = typeof(T).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
//make sure there is but 1 and use that
return (T)constructors.Single().Invoke(null);
}
catch {
//tell programmer to fix his stuff
throw new Exception(typeof(T)+ErrorMessage);
}
}
}
回答by Monotomy
It is possible without reflection.
没有反射是可能的。
We just need a generic class for the singleton pattern which takes two parameter - the implementation of the concrete singleton class and the interface for the concrete singleton. The generic singleton class implements the singleton pattern and all the stuff you need - for example logging, locks or what else.
我们只需要一个带有两个参数的单例模式的通用类——具体单例类的实现和具体单例的接口。通用单例类实现了单例模式和所有你需要的东西——例如日志记录、锁或其他什么。
using System;
using System.Diagnostics;
namespace Singleton
{
class Program
{
static void Main(string[] args)
{
Something.Instance.SayHello();
}
}
/// <summary>
/// Generic singleton pattern implementation
/// </summary>
public class SingletonImplementation<Implementation, ImplementationInterface>
where Implementation : class, ImplementationInterface, new()
{
private SingletonImplementation() { }
private static Implementation instance = null;
public static ImplementationInterface Instance
{
get
{
// here you can add your singleton stuff, which you don't like to write all the time
if ( instance == null )
{
instance = new Implementation();
}
return instance;
}
}
}
/// <summary>
/// Interface for the concrete singleton
/// </summary>
public interface ISomething
{
void SayHello();
}
/// <summary>
/// Singleton "held" or "wrapper" which provides the instance of the concrete singleton
/// </summary>
public static class Something
{
// No need to define the ctor private, coz you can't do anything wrong or useful with an instance of Something
// private Implementation();
/// <summary>
/// Like common: the static instance to access the concrete singleton
/// </summary>
public static ISomething Instance => SingletonImplementation<ImplementationOfSomething, ISomething>.Instance;
/// <summary>
/// Concrete singleton implementation
/// </summary>
private class ImplementationOfSomething : ISomething
{
// No need to define the ctor private, coz the class is private.
// private Implementation();
public void SayHello()
{
Debug.WriteLine("Hello world.");
}
}
}
}
回答by OpacANEBDOUR
This is an example in Cpp but you can transform it to any other language:
这是 Cpp 中的示例,但您可以将其转换为任何其他语言:
template < class T>
class singleton
{
private:
static T* _instance;
public:
static T* CreateInstance()
{
if (_instance == 0) _instance = new T;
return _instance;
}
static void Release()
{
if (_instance)
{
delete _instance;
_instance = 0;
}
}
};
template<class T> T* singleton<T>::_instance = 0;