【问题标题】:C# Singleton with constructor that accepts parameters带有接受参数的构造函数的 C# Singleton
【发布时间】:2010-11-10 12:13:18
【问题描述】:

我想创建一个静态类或单例类,它在其构造函数中接受对另一个对象的引用。静态类已经出来了,但我想我可以创建一个在其构造函数中接受参数的单例。到目前为止,我还没有运气弄清楚或在谷歌上搜索语法。这可能吗?如果是这样,我该怎么做?

很抱歉在最初的帖子中没有示例,我写的很匆忙。我觉得我的答案已经在回复中,但这里有一些我想要做的澄清:

我想创建一个特定类型的单个实例(称为 Singleton),但该类型的单个实例需要保存对不同对象的引用。

例如,我可能想创建一个单例“状态”类,它拥有一个 StringBuilder 对象和一个可以调用的 Draw() 方法,以便将所述 StringBuilder 写入屏幕。 Draw() 方法需要了解我的 GraphcisDevice 才能进行绘制。 所以我想这样做:

public class Status
{
private static Status _instance;
private StringBuilder _messages;
private GraphicsDevice _gDevice;

private Status(string message, GraphicsDevice device)
{
    _messages.Append(message);
    _gDevice = device;
}

// The following isn't thread-safe

// This constructor part is what I'm trying to figure out
public static Status Instance // (GraphicsDevice device) 
    {
    get
        {
        if (_instance == null)
            {
            _instance = new Status("Test Message!", device); 
            }
        return _instance;
        }
    }

public void UpdateMessage
...

public void Draw()
    {
    // Draw my status to the screen, using _gDevice and _messages
    }
}  

在整个代码中,我检索了我的状态单例并调用它的 UpdateMessage() 方法。

private Status _status = Status.Instance; // + pass reference to GraphicsDevice
_status.UpdateMessage("Foo!");

然后,在我的主类中,我还检索单例,并绘制它:

_status.Draw();

是的,这意味着无论我在哪里检索单例,我都需要通过传入对 GraphicsDevice 的引用来这样做,以防这是我第一次实例化单例。而且我可以/将使用不同的方法来检索像我的 Singleton 类中的 GraphicsDevice 这样基本的东西,例如在其他地方注册一个服务并在 Status 类中获取该服务。这个例子非常做作 - 我试图弄清楚 something 这样的模式是否是可能的。

【问题讨论】:

  • 添加了对我所问问题的更好解释。

标签: c# constructor singleton


【解决方案1】:

我认为您具体要求的内容如下所示:

public sealed class Singleton {
    static Singleton instance = null;
    static readonly object padlock = new Object();
    Object o;

    Singleton(Object _o) {
        o = _o;
    }

    public static Singleton Instance(Object _o) {
        lock (padlock) {
            if (instance == null) {
                instance = new Singleton(_o);
            }
            return instance;
        }
    }
}

Singleton s = Singleton.Instance(new Object());

不过,我怀疑已经发布的通用版本是您真正想要的。

【讨论】:

    【解决方案2】:

    你可以做的一件事可能是坚持你找到的单例样本,只公开一个属性(setter,如果需要,也添加 getter)并像使用它一样使用它 MySingleton.Instance.MyReference = new MyObject();

    如果你必须限制你的单例对象的使用,例如在设置引用之前对单例对象的任何操作都需要是非法的,你可以有一个私有的布尔标志,例如,hasBeenIntialized 和 MyReference setter 将在内部设置标志。所有其他方法将在执行开始时检查标志,并在 hasBeenInitialized 为 false 时调用任何方法时抛出异常。

    如果您需要只读行为,如果有人想要在 hasBeenInitialized 设置为 true 时分配不同的对象,您可能会在 MyReference 设置器中抛出异常。

    【讨论】:

      【解决方案3】:

      这通常被认为是一个坏主意,因为如果您打算接受一个对象引用或一个类型参数,您计划包装在一个类似单例的包装器中,您不能保证您在应用程序域。

      单例模式的全部意义在于控制一种类型的单个实例,以便该类型只能存在一个实例。如果您允许传入一个实例,或者如果您制作了一个通用的单例提供程序,则您不能保证您的实例是 only 实例。

      假设我有一个SingletonFactory<T>,它允许我围绕传递给工厂的任何类型创建一个单例。那会很方便,可以让我做这样的事情:

      SingletonFactory<Foo>.Instance;
      

      但是是什么阻止了我也这样做:

      Foo foo = new Foo();
      

      糟糕,Foo 看起来不再是单例了,因为我可以创建任意数量的实例。为了使单例模式起作用,您需要能够完全控制需要限制其实例的类型。这就是为什么你不应该使用像我的SingletonFactory&lt;T&gt; 这样的东西。

      注意: 接受对象实例的非泛型单例也是如此。我相信您可以从我之前的示例中推断出许多类似的原因,为什么接受和对象引用的单例包装器也是一个坏主意。

      【讨论】:

        【解决方案4】:

        你需要一个私有的构造函数,然后是一个getInstance方法,这个方法是谁应该接收参数,构造函数必须是私有的,它也可以有参数,但是getInstance应该传递它,不是你。顺便说一句,你在做什么?一些真实的例子可能会有所帮助。

        【讨论】:

          【解决方案5】:

          您所描述的是通用单例。它看起来像这样:

          public class SingletonProvider <T> where T:new()
          {
              SingletonProvider() {}
          
              public static T Instance
              {
                  get { return SingletonCreator.instance; }
              }
          
              class SingletonCreator
              {
                  static SingletonCreator() { }
          
                  internal static readonly T instance = new T();
              }
          }
          

          http://www.codeproject.com/KB/cs/genericsingleton.aspx

          【讨论】:

          • 如何保证你的应用程序中没有任何其他类型 T 的实例?这不是真正的单身人士。
          • 我假设提出问题的人已经明白他不能将类型用于其他任何事情。他要了刀,我没有告诉他怎么处理。
          • Singleton 与 Singleton 是不同的类型,所以没关系。我想,只有当它们作为创建单例的基类时,通用单例才有意义。
          猜你喜欢
          • 1970-01-01
          • 2011-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多