具有可触发初始化的C#单例模式

具有可触发初始化的C#单例模式,c#,.net,singleton,initialization,C#,.net,Singleton,Initialization,我需要一个单身汉: 是惰性负载吗 线程安全吗 在构造时加载一些值 可以随时查询这些值 初始化可能在某个精确的时间发生,在查询开始之前-因此我必须能够以某种方式从外部触发它。当然,多次触发只能进行一次初始化 我使用.NET3.5 我从Jon Skeet的(第5版)开始使用静态子类: public sealed class Singleton { IEnumerable<string> Values {get; private set;} private Single

我需要一个单身汉:

  • 是惰性负载吗
  • 线程安全吗
  • 在构造时加载一些值
  • 可以随时查询这些值
  • 初始化可能在某个精确的时间发生,在查询开始之前-因此我必须能够以某种方式从外部触发它。当然,多次触发只能进行一次初始化
我使用.NET3.5

我从Jon Skeet的(第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();
    }
} 

看起来你可以做到:

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

    }
} 
公共密封类单例
{
IEnumerable值{get;private set;}
私有单例(bool-loadDefaults)
{
如果(加载默认值)
value=new[]{“quick”、“brown”、“fox”};
其他的
Values=new[]{“另一个”、“集合”、“of”、“值”};
}
公共静态单例实例{get{return Nested.Instance;}}
公共静态void Initialize(){
Nested.Initialize();
}
私有类嵌套
{
//显式静态构造函数告诉C#编译器
//不将类型标记为beforefieldinit
静态嵌套()
{
}
内部静态只读单例实例=新单例(true);
私有静态对象instanceLock=新对象();
私有静态布尔值初始化=false;
公共静态void Initialize(){
锁(instanceLock){
如果(!i初始化){
isInitialized=true;
实例=新单例(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();
    }
} 
公共密封类单例
{
IEnumerable值{get;private set;}
私人单身人士()
{
value=new[]{“quick”、“brown”、“fox”};
}
公共静态单例实例{get{return Nested.Instance;}}
私有静态对象instanceLock=新对象();
私有静态布尔值初始化=false;
公共静态void Initialize(){
锁(instanceLock){
如果(!i初始化){
isInitialized=true;
value=new[]{“另一个”、“集合”、“of”、“值”};
}
}
}
私有类嵌套
{
//显式静态构造函数告诉C#编译器
//不将类型标记为beforefieldinit
静态嵌套()
{
}
内部静态只读单例实例=新单例();
}
} 
第三种变体基于不可变注释和嵌套类注释的删除:

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();
            }
        }
    }
} 
公共密封类单例
{
IEnumerable值{get;private set;}
私人单身人士()
{
value=new[]{“quick”、“brown”、“fox”};
}
私有静态单例实例;
私有静态对象instanceLock=新对象();
公共静态单例实例{
得到{
初始化();
返回实例;
}
}
公共静态void Initialize(){
if(实例==null){
锁(instanceLock){
if(实例==null)
instance=newsingleton();
}
}
}
} 

您可以设置一个可以从外部触发的初始化方法,如果您需要稍后进行初始化,但是如果每次触发的值不同,那么它就不能是静态的,这违反了单例模式

基于您的示例(没有变量),我假设您只是延迟初始化(例程而不是构造函数),但您的问题表明您需要不同的值,但是如果多个初始化发生在一起,它只初始化一次,所以我对此有点困惑


我不确定您是否需要单例实现,但如果没有关于Initialize()是否每次运行相同的代码或是否具有某种类型的变量性质的信息,则无法完全回答。

您可以使用双重检查锁定模式。只需在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;
                 }
              }
            }
        }

.......................

}

你可以这样做

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");
            }
        }
    }
}
哪个输出

- 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
公共类单例,其中T:class,new()
{
私有静态T实例;
公共静态T实例
{
得到
{
if(实例==null)
{
抛出新异常(“singleton需要在使用前进行初始化”);
}
返回实例;
}
}
公共静态无效初始化(操作初始化操作)
{
锁(类型(单件))
{
if(实例!=null)
{
返回;
}
实例=新的T();
初始化操作(实例);
}
}
}

我的第一个想法是只使用一个分配给singleton实例的一次性变量,它(可能?)会触发初始化

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;
}

撇开编译器优化不谈,我认为这可以解决所有的需求。

公共静态void Initialize(){Singleton instance=instance;}
问题出在哪里?您的需求之一是“多次触发应该只进行一次初始化”,但是你说Jon Skeet模式的缺点之一是初始化“不能发生多次”。你真正需要的是什么?与你的问题没有直接关系,但你绝对确定你需要一个单例,我很少使用它们,而不会造成比它们解决的问题多得多的问题。@vickirk曾参与过一个名为“GlobalInstance”的单例引用已知宇宙中所有其他事物的项目,我明白你的意思。然而,我确实倾向于认为这是(为数不多的
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;
}