【问题标题】:Using singleton instead of a global static instance使用单例而不是全局静态实例
【发布时间】:2010-04-06 22:56:27
【问题描述】:

我今天遇到了一个问题,一位朋友建议我使用全局静态实例或更优雅的单例模式。我花了几个小时阅读有关单身人士的文章,但仍有几件事让我无法理解。

背景: 我试图完成的是创建一个 API 实例并在我的所有类中使用这个实例(而不是建立新的连接等)。

似乎有大约 100 种创建单例的方法,但在 yoda 的帮助下,我找到了一些线程安全的示例。 ..so给出以下代码:

public sealed class Singleton
{
     public static Singleton Instance { get; private set; }

     private Singleton()
     {
        APIClass api = new APIClass();  //Can this be done?
     }

     static Singleton() { Instance = new Singleton(); }
}

您将如何/在哪里实例化这个新类以及如何从单独的类中调用它?

编辑: 我意识到单例类可以用类似的东西来调用

Singleton obj1 = Singleton.Instance();

但是我能否访问 API 类中的方法(即 obj1.Start)? (不是我需要,只是问)

编辑#2:我在检查答案时可能有点为时过早,但我确实有一件小事仍在给我带来问题。 API 启动得很好,不幸的是我能够启动两个实例?

新代码

public sealed class SingletonAPI
{
 public static SingletonAPI Instance { get; private set; }

 private SingletonAPI() {}

 static SingletonAPI() { Instance = new SingletonAPI(); }     

 // API method:
 public void Start() { API myAPI = new API();}
 }

但如果我尝试做这样的事情......

SingletonAPI api = SingletonAPI.Instance;
api.Start();
SingletonAPI api2 = SingletonAPI.Instance;  // This was just for testing.
api2.Start();

我收到一条错误消息,提示我无法启动多个实例。

【问题讨论】:

  • 您还应该添加一个私有构造函数,以防止另一个类实例化您的 Singleton 的副本。
  • 您将无法调用 api 类上的方法,因为它没有被公开。
  • 确实,您可以在私有 Singleton 构造函数中实例化一个 APIClass 对象。由于私有构造函数只会被调用一次,因此从静态构造函数来看,AFAIK 看起来都不错。不过,您将 APIClass 声明为局部变量,因此范围仅在私有构造函数内。如果您想在此之外使用它,至少必须将其重新声明为私有成员。
  • 附带说明,如果您已经有一个封装完整 API 的 API 类,您始终可以将 APIClass 实例化为类的静态成员,而不是将其包装在自己的 Singleton 中。
  • Farstucker,关于您的编辑#2,首先我认为您理解这一点,但在您的示例中 api 和 api2 指的是完全相同的对象 - 这是工作中的单例。其次,不要在公共方法中实例化您的 API。在单例的私有构造函数中实例化它。这样它只会被实例化一次。 (这正是我在回答中显示的内容。我不确定,也许您在编写编辑#2 后看到了我的回答)

标签: c# singleton


【解决方案1】:

为什么不向你的单例添加一个公共 APIClass 属性?

public sealed class Singleton
{
     public static Singleton Instance { get; private set; }

     private APIClass _APIClass; 

     private Singleton()
     {
        _APIClass = new APIClass();  
     }

     public APIClass API { get { return _APIClass; } }

     static Singleton() { Instance = new Singleton(); }     
}

那么您的呼叫站点如下所示:

Singleton.Instance.API.DoSomething();

或者,如果您是 API 类的作者,您可以将其本身设为单例,而不是将其包装在单例中:

public sealed class SingletonAPI
{
     public static SingletonAPI Instance { get; private set; }

     private SingletonAPI() {}

     static SingletonAPI() { Instance = new SingletonAPI(); }     

     // API method:
     public void DoSomething() { Console.WriteLine("hi"); }
}

API 调用:

SingletonAPI.Instance.DoSomething();

【讨论】:

  • @charles 非常感谢,这正是我所需要的。
【解决方案2】:

这里是official Microsoft approach

单例的美妙之处在于您可以在代码中的任何位置使用和访问它,而无需创建类的实例。事实上,这就是它存在的理由,例如一个类的单个实例

Singleton.Instance.MyValueSingleton.Instance.DoSomething();

【讨论】:

    【解决方案3】:

    您不会实例化该类 - 您使用的模式基本上会在第一次使用时自行实例化。您使用的方法的优点是它是线程安全的(只会实例化一次,无论有多少线程尝试访问它)、惰性(在您尝试访问 Singleton 类之前它不会实例化)和简单正在实施中。

    你需要做的就是这样做:

     Singleton.Instance.MyMethodOnSingleton();
    

    或者,或者:

     Singleton myInstance = Singleton.Instance; // Will always be the same instance...
     myInstance.DoSomething();
    

    【讨论】:

    • 我也推荐 Farstucker 在 msdn msdn.microsoft.com/en-us/library/ms998558.aspx阅读关于单身人士的文章
    • 信不信由你,我确实读过。我想我只是对如何实例化一个完全不同的类并在全局范围内使用它感到困惑。我添加了一些代码来帮助解释我想要做什么。
    猜你喜欢
    • 2012-04-06
    • 1970-01-01
    • 2011-02-27
    • 2013-11-12
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多