带有接受参数的构造函数的 C# Singleton

Posted

技术标签:

【中文标题】带有接受参数的构造函数的 C# Singleton【英文标题】:C# Singleton with constructor that accepts parameters 【发布时间】: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 这样的模式是否是可能的。

【问题讨论】:

添加了对我所问问题的更好解释。 【参考方案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 是不同的类型,所以没关系。我想,只有当它们作为创建单例的基类时,通用单例才有意义。

以上是关于带有接受参数的构造函数的 C# Singleton的主要内容,如果未能解决你的问题,请参考以下文章

从 2.8.4 更新到 27.1.1 后,C# CsvWriter 抛出“CsvWriter 不包含接受 1 个参数的构造函数”

c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?

是否可以有一个带有 1 个未声明类型的输入参数的构造函数?

从 Powershell 调用带有数组参数的构造函数

使用 COM 的参数化构造函数实例化类

使构造函数仅接受 C# 中具有 [Serializable] 属性的对象