我需要一个单身:
我使用.NET 3.5。
我使用静态子类开始使用Jon Skeet的implementation(第5版):
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
除了“从外部触发初始化”外,几乎所有方框都会打勾。由于实际初始化发生在ctor内部,因此不会发生多次。
如何实现这一目标?
单身人士会像这样使用:
public static void Main(){
//do stuff, singleton should not yet be initialized.
//the time comes to initialize the singleton, e.g. a database connection is available
//this may be called 0 or more times, possibly on different threads
Singleton.Initialize();
Singleton.Initialize();
Singleton.Initialize();
//actual call to get retrieved values, should work
var retrieveVals = Singleton.Instance.Values;
}
答案 0 :(得分:3)
好像你可以这样做:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton(bool loadDefaults)
{
if (loadDefaults)
Values = new[]{"quick", "brown", "fox"};
else
Values = new[]{"another", "set", "of", "values"};
}
public static Singleton Instance { get { return Nested.instance; } }
public static void Initialize() {
Nested.Initialize();
}
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton(true);
private static object instanceLock = new object();
private static bool isInitialized = false;
public static void Initialize() {
lock(instanceLock) {
if (!isInitialized) {
isInitialized = true;
instance = new Singleton(false);
}
}
}
}
}
或者创建一个将要更新的单个实例:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
public static Singleton Instance { get { return Nested.instance; } }
private static object instanceLock = new object();
private static bool isInitialized = false;
public static void Initialize() {
lock(instanceLock) {
if (!isInitialized) {
isInitialized = true;
Instance.Values = new[]{"another", "set", "of", "values"};
}
}
}
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
第三种变体基于您的不可变注释和删除嵌套类注释:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
private static Singleton instance;
private static object instanceLock = new object();
public static Singleton Instance {
get {
Initialize();
return instance;
}
}
public static void Initialize() {
if (instance == null) {
lock(instanceLock) {
if (instance == null)
instance = new Singleton();
}
}
}
}
答案 1 :(得分:1)
我的第一个想法就是使用分配给单例实例的一次性变量,这可能(可能是?)触发初始化
static Main()
{
var unused = Singleton.Instance;
//this should initialize the singleton, unless the compiler optimizes it out.
//I wonder if the compiler is smart enough to see this call has side effects.
var vals = Singleton.Instance.Values;
}
...但是副作用编程是我努力避免的,所以让我们的意图更加清晰。
public class Singleton {
public static void Initialize() {
//this accesses the static field of the inner class which triggers the private Singleton() ctor.
Instance._Initialize();
}
private void _Initialize()
{ //do nothing
}
[the rest as before]
}
所以用法是:
static Main()
{
//still wondering if the compiler might optimize this call out
Singleton.Initialize();
var vals = Singleton.Instance.Values;
}
顺便说一句,这也有效:
static Main()
{
var vals = Singleton.Instance.Values;
}
除了编译器优化之外,我认为这可以满足所有要求。
答案 2 :(得分:0)
你可以设置一个可以从外部触发的Initialize方法,如果你需要稍后进行初始化,但是如果每次触发时值都不同,那么它就不能是静态的,这违反了Singleton模式
根据你的例子,它没有变量,我假设你只是在初始化发生时延迟(例程而不是构造函数),但你的问题表明你想要不同的值,但如果多个初始化发生在一起,它只会初始化曾经,所以我对此感到有点困惑。
我不确定你是否只需要Singleton implmentation,但如果没有关于Initialize()每次是否运行相同的代码或具有某种类型的变量性质的信息,则无法完全回答。
答案 3 :(得分:0)
您可以使用双重检查锁定模式。只需在您的Singleton类中添加以下代码:
public sealed class Singleton
{
..........................
private static object locker = new object();
private static bool initialized = false;
public static void Initialize() {
if (!initialized){
lock(locker) {
if (!initialized){
//write initialization logic here
initialized = true;
}
}
}
}
.......................
}
答案 4 :(得分:0)
你可以做这样的事情
public sealed class Singleton
{
IEnumerable<string> Values { get; set; }
private Singleton()
{
Console.WriteLine("-- Private Singleton constructor");
Values = new[] { "quick", "brown", "fox" };
}
public static Singleton Instance
{
get
{
Console.WriteLine("- Singleton Instance");
return Nested.instance;
}
}
public static void Initialize()
{
Console.WriteLine("- Singleton Initialize");
Nested.Initialize();
}
internal class Nested
{
private static object syncRoot = new object();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
Console.WriteLine("-- Static Nested constructor");
}
internal static readonly Singleton instance = new Singleton();
internal static void Initialize()
{
lock (syncRoot)
{
Console.WriteLine("-- Locked");
Console.WriteLine("--- Nested Initialize");
Console.WriteLine("-- Unlocked");
}
}
}
}
用法
class Program
{
static void Main(string[] args)
{
var i = Singleton.Instance;
i = Singleton.Instance;
Console.WriteLine("-----");
Singleton.Initialize();
Singleton.Initialize();
Singleton.Initialize();
Console.Read();
}
}
哪个输出
- Singleton Instance
-- Private Singleton constructor
-- Static Nested constructor
- Singleton Instance
-----
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
答案 5 :(得分:0)
public class Singleton<T> where T : class, new()
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
throw new Exception("singleton needs to be initialised before use");
}
return instance;
}
}
public static void Initialise(Action<T> initialisationAction)
{
lock(typeof(Singleton<T>))
{
if (instance != null)
{
return;
}
instance = new T();
initialisationAction(instance);
}
}
}