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

我需要一个单身人士:

  • 是懒加载的
  • 是线程安全的
  • 在施工时加载一些值
  • 这些值可以随时查询
  • 在查询开始之前,初始化可能会在某个精确时间发生 - 所以我必须能够以某种方式从外部触发它。 当然,多次触发只能进行一次初始化。
  • 我使用.NET 3.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();
        }
    } 
    

    除了“从外部触发初始化”之外,这几乎包括所有的方框。 由于实际初始化发生在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;
    
    }
    

    似乎你可以这样做:

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

    如果你需要初始化以后发生,你可以设置一个可以从外部触发的Initialize方法,但是如果每次触发时这些值不同,那么它不能是静态的,这违反了Singleton模式。

    根据你的没有变量的例子,我假设你只是在初始化发生时推迟(例程而不是构造函数),但是你的问题表明你需要不同的值,但是如果多个初始化紧密结合在一起,它只会初始化一次,所以我对此有点困惑。

    我不确定你是否只需要一个Singleton,但是如果没有关于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;
                     }
                  }
                }
            }
    
    .......................
    
    }
    
    链接地址: http://www.djcxy.com/p/8735.html

    上一篇: C# Singleton pattern with triggerable initialization

    下一篇: How to copy to clipboard in Vim?