26

如何在 C# 中实现单例模式?我想将我的常量和一些基本函数放入其中,因为我在项目中到处使用它们。我想让它们“全局”,而不需要手动绑定我创建的每个对象。

4

16 回答 16

29

如果您只是存储一些全局值并且有一些不需要状态的方法,则不需要单例。只需将类及其属性/方法设为静态即可。

public static class GlobalSomething
{
   public static int NumberOfSomething { get; set; }

   public static string MangleString( string someValue )
   {
   }
}

当你有一个普通的有状态的类时,单例是最有用的,但你只想要其中一个。其他人提供的链接对于探索单例模式应该很有用。

于 2008-10-29T13:14:40.377 回答
6

Singleton != Global. 您似乎在寻找关键字static

于 2008-10-29T13:13:02.843 回答
5

只有当这两个条件都为真时,单例才有意义:

  1. 对象必须是全局的
  2. 必须只存在一个对象的实例

请注意,#2 并不意味着您希望对象只有一个实例——如果是这样,只需实例化一次——这意味着必须存在(如,这不正确是很危险的)只能是一个实例。

如果您想要全局,只需创建某个(非符号)对象的全局实例(或使其成为静态或其他)。如果您只想要一个实例,那么静态是您的朋友。此外,只需实例化一个对象。

反正这是我的意见。

于 2008-10-29T13:27:58.587 回答
5

您可以真正简化单例实现,这就是我使用的:

    internal FooService() { }        
    static FooService() { }

    private static readonly FooService _instance = new FooService();

    public static FooService Instance
    {
        get { return _instance; }
    }
于 2008-10-29T14:47:20.237 回答
4

嗯,这一切似乎有点复杂。

为什么需要依赖注入框架来获取单例?对于某些企业应用程序来说,使用 IOC 容器是可以的(当然,只要它没有被过度使用),但是,啊,这家伙只是想知道如何实现该模式。

为什么不总是急切地实例化,然后提供一个返回静态的方法,上面写的大部分代码然后就消失了。遵循古老的 C2 格言 - DoTheSimplestThingThatCouldPossiblyWork...

于 2008-10-30T12:00:28.183 回答
3

我建议您阅读MSDN 上提供的Exploring the Singleton Design Pattern文章。它详细介绍了使模式易于实现的框架的特性。

顺便说一句,我会查看SO 有关 Singletons 的相关阅读

于 2008-10-29T13:12:13.780 回答
3

忽略你是否应该使用单例模式的问题,这已经在别处讨论过,我会像这样实现一个单例:

/// <summary>
/// Thread-safe singleton implementation
/// </summary>
public sealed class MySingleton {

    private static volatile MySingleton instance = null;
    private static object syncRoot = new object();

    /// <summary>
    /// The instance of the singleton
    /// safe for multithreading
    /// </summary>
    public static MySingleton Instance {
        get {
            // only create a new instance if one doesn't already exist.
            if (instance == null) {
                // use this lock to ensure that only one thread can access
                // this block of code at once.
                lock (syncRoot) {
                    if (instance == null) {
                        instance = new MySingleton();
                    }
                }
            }
            // return instance where it was just created or already existed.
            return instance;
        }
    }


    /// <summary>
    /// This constructor must be kept private
    /// only access the singleton through the static Instance property
    /// </summary>
    private MySingleton() {

    }

}
于 2008-10-29T13:43:37.680 回答
3

如果您想要松散耦合的设计,静态单例几乎是一种反模式。尽可能避免,除非这是一个非常简单的系统,否则我建议您查看许多可用的依赖注入框架之一,例如http://ninject.org/http://code.google.com/p /autofac/

要在 autofac 中注册/使用配置为单例的类型,您可以执行以下操作:

var builder = new ContainerBuilder()
builder.Register(typeof(Dependency)).SingletonScoped()
builder.Register(c => new RequiresDependency(c.Resolve<Dependency>()))

var container = builder.Build();

var configured = container.Resolve<RequiresDependency>();

顺便说一句,公认的答案是一个糟糕的解决方案,至少检查实际实施该模式的人。

于 2008-10-29T14:43:21.867 回答
2
public class Globals
{
    private string setting1;
    private string setting2;

    #region Singleton Pattern Implementation

    private class SingletonCreator
    {
        internal static readonly Globals uniqueInstance = new Globals();

        static SingletonCreator()
        {
        }
    }

    /// <summary>Private Constructor for Singleton Pattern Implementaion</summary>
    /// <remarks>can be used for initializing member variables</remarks>
    private Globals()
    {

    }

    /// <summary>Returns a reference to the unique instance of Globals class</summary>
    /// <remarks>used for getting a reference of Globals class</remarks>
    public static Globals GetInstance
    {
        get { return SingletonCreator.uniqueInstance; }
    }

    #endregion

    public string Setting1
    {
        get { return this.setting1; }
        set { this.setting1 = value; }
    }

    public string Setting2
    {
        get { return this.setting2; }
        set { this.setting2 = value; }
    }

    public static int Constant1 
    {
        get { reutrn 100; }
    }

    public static int Constat2
    {
        get { return 200; }
    }

    public static DateTime SqlMinDate
    {
        get { return new DateTime(1900, 1, 1, 0, 0, 0); }
    }

}
于 2008-12-17T04:47:06.660 回答
2

我喜欢这种模式,尽管它不会阻止某人创建非单例实例。有时,最好教育团队中的开发人员使用正确的方法,而不是竭尽全力防止某些笨蛋以错误的方式使用您的代码……

    public class GenericSingleton<T> where T : new()
    {
        private static T ms_StaticInstance = new T();

        public T Build()
        {
            return ms_StaticInstance;
        }
    }

...
    GenericSingleton<SimpleType> builder1 = new GenericSingleton<SimpleType>();
    SimpleType simple = builder1.Build();

这将为您提供一个实例(以正确的方式实例化)并且实际上是惰性的,因为在调用 Build() 之前不会调用静态构造函数。

于 2008-12-21T19:04:38.607 回答
1

您所描述的只是静态函数和常量,而不是单例。单例设计模式(很少需要)描述了一个实例化的类,但在第一次使用时自动实例化一次

它将延迟初始化与检查结合起来,以防止多次实例化。它只对包装一些物理上单一的概念的类真正有用,例如围绕硬件设备的包装器。

静态常量和函数就是这样:根本不需要实例的代码。

问问自己这个问题:“如果有多个实例,这个类会中断吗?” 如果答案是否定的,则不需要单例。

于 2008-10-29T17:53:54.227 回答
1

嗯...很少有具有相关功能的常量...通过枚举不是更好吗?我知道您可以使用方法和所有方法在 Java 中创建自定义枚举,在 C# 中也应该可以实现,如果不直接支持,那么可以使用带有私有构造函数的简单类单例来完成。

如果您的常量在语义上相关,您应该考虑枚举(或等效概念),您将获得 const 静态变量的所有优势 + 您将能够利用编译器的类型检查来发挥您的优势。

我的 2 美分

于 2008-10-29T18:45:54.590 回答
1

就我个人而言,我会选择一个依赖注入框架,比如 Unity,它们都能够在容器中配置单例项,并通过从类依赖转移到接口依赖来改善耦合。

于 2008-10-30T11:37:06.000 回答
0

通过隐藏公共构造函数,添加一个私有静态字段来保存这个唯一的实例,并添加一个静态工厂方法(带有惰性初始化器)来返回那个单一的实例

public class MySingleton   
{  
    private static MySingleton sngltn; 
    private static object locker;  
    private MySingleton() {}   // Hides parameterless ctor, inhibits use of new()   
    public static MySingleton GetMySingleton()       
    {     
        lock(locker)
            return sngltn?? new MySingleton();
    }   
}
于 2008-10-30T01:55:17.097 回答
0

我使用单例模式为我的项目编写了一个类。这是非常容易使用。希望它对你有用。请找到以下代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TEClaim.Models
{
public class LogedinUserDetails
{
    public string UserID { get; set; }
    public string UserRole { get; set; }
    public string UserSupervisor { get; set; }
    public LogedinUserDetails()
    {

    }

    public static LogedinUserDetails Singleton()
    {
        LogedinUserDetails oSingleton;

        if (null == System.Web.HttpContext.Current.Session["LogedinUserDetails"])
        {               
            oSingleton = new LogedinUserDetails();
            System.Web.HttpContext.Current.Session["LogedinUserDetails"] = oSingleton;
        }
        else
        {              
            oSingleton = (LogedinUserDetails)System.Web.HttpContext.Current.Session["LogedinUserDetails"];
        }

        //Return the single instance of this class that was stored in the session
        return oSingleton;
    }
}
}

现在您可以像这样在应用程序中为上述代码设置变量值。

[HttpPost]
public ActionResult Login(FormCollection collection)
{
  LogedinUserDetails User_Details = LogedinUserDetails.Singleton();
  User_Details.UserID = "12";
  User_Details.UserRole = "SuperAdmin";
  User_Details.UserSupervisor = "815978";
  return RedirectToAction("Dashboard", "Home");
}

你可以像这样检索这些值..

public ActionResult Dashboard()
    {
        LogedinUserDetails User_Details = LogedinUserDetails.Singleton();
        ViewData["UserID"] = User_Details.UserID;
        ViewData["UserRole"] = User_Details.UserRole;
        ViewData["UserSupervisor"] = User_Details.UserSupervisor;

        return View();
    }
于 2017-12-09T13:27:50.347 回答
0

在 c# 中它可能是(线程安全以及延迟初始化):

public sealed class MySingleton
{
    static volatile Lazy<MySingleton> _instance = new Lazy<MySingleton>(() => new MySingleton(), true);
    public static MySingleton Instance => _instance.Value;
    private MySingleton() { }
}
于 2018-04-05T08:25:26.127 回答