C# 带参数的单态

C# 带参数的单态,c#,design-patterns,parameters,singleton,arguments,C#,Design Patterns,Parameters,Singleton,Arguments,我需要用一些参数实例化一个单例类。我现在的做法是: class SingletonExample { private SingletonExample mInstance; //other members... private SingletonExample() { } public SingletonExample Instance { get { if

我需要用一些参数实例化一个单例类。我现在的做法是:

class SingletonExample
{
     private SingletonExample mInstance;
     //other members... 
     private SingletonExample()
     {

     } 
     public SingletonExample Instance
     {
         get
         {
              if (mInstance == null)
              {
                  throw new Exception("Object not created");
              }
              return mInstance;
         }
     }

     public void Create(string arg1, string arg2)
     {
         mInstance = new SingletonExample();
         mInstance.Arg1 = arg1;
         mInstance.ObjectCaller = new ObjectCaller(arg2);
         //etc... basically, create object...
     } 
}
实例是“迟创建”的,这意味着我没有应用程序启动时所需的所有参数

一般来说,我不喜欢强制对方法调用进行排序,但我看不到其他方法。IoC也不会解决这个问题,因为我可以在容器中注册它,我也可以调用Create()

你认为这是个好方案吗?你还有别的想法吗


编辑:我知道我所写的示例不是线程安全的,线程安全不是问题的一部分

我实际上在你的代码中看不到一个单例。 使用一个静态的、参数化的getInstance方法,该方法返回singleton,如果以前没有使用过它,则创建它。

更好的答案:

  • 创建一个接口:
    ISingleton
    (包含您希望它执行的任何操作)

  • 您的类型:
    Singleton:ISingleton

  • 假设您有权访问UnityContainer:

  • IUnityContainer\u singletonContainer=new UnityContainer();//或初始化容器的任何代码

  • 当您准备好创建类型使用时(假设您使用Unity for DI):
  • \u singletonContainer.RegisterType(typeof(ISingleton),newsingleton(params))

  • 如果您想获得singleton,只需使用:
  • var localSingletonVar=_singletonContainer.Resolve()

    注意:如果容器没有为ISingleton接口注册类型,那么它应该抛出异常,或者返回null

    旧答案:

    public class Singleton
    {
    
        private static Singleton instance = null;
    
        private Singleton(String arg1, String arg2)
        {
        }
    
        public static Singleton getInstance(String arg1, String arg2)
        {
            if (instance != null)
            {
                throw new InvalidOperationException("Singleton already created - use getinstance()");
            }
            instance = new Singleton(arg1, arg2);
            return instance;
        }
    
        public static Singleton getInstance()
        {
            if (instance == null)
                throw new InvalidOperationException("Singleton not created - use GetInstance(arg1, arg2)");
            return instance;
        }
    }
    
    我会使用类似的方法(您可能需要检查实例是否也创建了),或者,如果您的DI容器支持对未注册的类型抛出异常,我也会这样做


    收件人:非线程安全代码:)

    带有参数的单例对我来说很可疑

    考虑一下特瓦的答案和以下代码:

    Singleton x = Singleton.getInstance("hello", "world");
    Singleton y = Singleton.getInstance("foo", "bar");
    
    显然,x==y和y使用x的创建参数,而y的创建参数被忽略。结果可能是。。。至少让人困惑

    如果你真的,真的觉得你必须这样做,就这样做:

    class SingletonExample
    {
         private static SingletonExample mInstance;
         //other members... 
         private SingletonExample()
         {  // never used
            throw new Exception("WTF, who called this constructor?!?");
         }
         private SingletonExample(string arg1, string arg2)
         {
             mInstance.Arg1 = arg1;
             mInstance.ObjectCaller = new ObjectCaller(arg2);
             //etc... basically, create object...    
         } 
         public static SingletonExample Instance
         {
             get
             {
                  if (mInstance == null)
                  {
                      throw new Exception("Object not created");
                  }
                  return mInstance;
             }
         }
    
         public static void Create(string arg1, string arg2)
         {
             if (mInstance != null)
             {
                 throw new Exception("Object already created");
             }
             mInstance = new SingletonExample(arg1, arg2);             
         } 
    }
    

    在多线程环境中,添加同步以避免竞争条件。

    Singleton很难看,但由于用户whateva不屑于修改自己的代码

    public class Singleton 
    { 
        private static Singleton _instance = null; 
    
        private static Object _mutex = new Object();
    
        private Singleton(object arg1, object arg2) 
        { 
            // whatever
        } 
    
        public static Singleton GetInstance(object arg1, object arg2)
        { 
            if (_instance == null) 
            { 
              lock (_mutex) // now I can claim some form of thread safety...
              {
                  if (_instance == null) 
                  { 
                      _instance = new Singleton(arg1, arg2);
                  }
              } 
            }
    
            return _instance;
        }
    }  
    
    斯基特在几年前写过这篇博客,我认为,这是相当可靠的。没有例外的必要,你不需要记住什么样的对象应该是单态的,当你搞错的时候处理它的影响


    编辑:类型与您想要的用途无关,
    对象仅为方便起见在此处使用。

    annakata提供的双锁单例解决方案不会每次在所有平台上都有效。这种方法有一个缺陷,这是有充分记录的。不要使用这种方法,否则最终会出现问题

    解决此问题的唯一方法是使用volatile关键字,例如

    private static volatile Singleton m_instance = null;
    
    这是唯一的线程安全方法。

    如果您使用的是.NET 4(或更高版本),则可以使用System.Lazy类型。 它将为您解决线程安全问题,并延迟执行,这样您就不会不必要地创建实例。 这样,代码就简洁明了了

    public sealed class Singleton
    {
        private static readonly Lazy<Singleton> lazy =
            new Lazy<Singleton>(() => new Singleton(),LazyThreadSafetyMode.ExecutionAndPublication);
    
        private Singleton()  {  }
    
        public static Singleton Instance { get { return lazy.Value; } }
    }
    
    公共密封类单例
    {
    私有静态只读惰性=
    新的Lazy(()=>newsingleton(),LazyThreadSafetyMode.ExecutionAndPublication);
    私有单例(){}
    公共静态单例实例{get{return lazy.Value;}}
    }
    
    ///具有双重检查模式和实例参数的通用单例
    /// 
    公共类SingleObject,其中T:class,new()
    {
    ///锁定对象
    私有静态只读对象_lockingObject=新对象();
    ///实例
    私有静态T_singleObject;
    ///受保护导体
    受保护的SingleObject()
    {
    }
    ///带参数的实例
    ///参数
    ///实例
    公共静态T实例(params dynamic[]param)
    {
    如果(_singleObject==null)
    {
    锁定(锁定对象)
    {
    如果(_singleObject==null)
    {
    _singleObject=(T)Activator.CreateInstance(typeof(T),param);
    }
    }
    }
    返回_singleObject;
    }
    }
    
    这不是单身汉。互斥在哪里?(即
    )。加上实例的
    getter
    应该是创建实例,而不是创建ctor——这就是重点。我同意RPM1984,这不是一个单例。您的参数是否可以更改,或者在应用程序的整个生命周期中它们是否相同?单例不应该依赖于某个变量,它可以依赖于配置或另一个单例。然而,仔细想想你的设计,问问自己你是否需要一个单身汉。过度使用单例对你的设计来说真的很糟糕。它是单例的,相信我:)getter不能创建实例,因为它没有参数-它可以有参数,但是这样写更方便。而且,参数一旦获得就不会改变。参数从何而来?@mastoj-来自某个服务调用-它是半静态数据,在我调用它之后是静态的。现在,这是一个单例,不是我显式地使用它们(我让DI来做,并且只用于日志记录之类的事情)+1我会继续假设特瓦决定否决的是一个功能正确的答案。不,他没有(看他的个人资料)。不管怎么说,这些关于单身汉的谈话让我昏昏欲睡,我要去睡觉了谈论修复你的代码。。。天哪,这是马车。为您修复了它。T1,T2不是泛型,只是真实类型的代理。-1我不同意这个解决方案,因为我认为您建议在不应该使用is的地方使用单例模式。单身汉是一个只有
    /// <summary> Generic singleton with double check pattern and with instance parameter </summary>
    /// <typeparam name="T"></typeparam>
    public class SingleObject<T> where T : class, new()
    {
        /// <summary> Lock object </summary>
        private static readonly object _lockingObject = new object();
    
        /// <summary> Instance </summary>
        private static T _singleObject;
    
        /// <summary> Protected ctor </summary>
        protected SingleObject()
        {
        }
    
        /// <summary> Instance with parameter </summary>
        /// <param name="param">Parameters</param>
        /// <returns>Instance</returns>
        public static T Instance(params dynamic[] param)
        {
            if (_singleObject == null)
            {
                lock (_lockingObject)
                {
                    if (_singleObject == null)
                    {
                        _singleObject = (T)Activator.CreateInstance(typeof(T), param);
                    }
                }
            }
            return _singleObject;
        }
    }