如何在 C# 中实现单例模式?我想将我的常量和一些基本函数放入其中,因为我在项目中到处使用它们。我想让它们“全局”,而不需要手动绑定我创建的每个对象。
16 回答
如果您只是存储一些全局值并且有一些不需要状态的方法,则不需要单例。只需将类及其属性/方法设为静态即可。
public static class GlobalSomething
{
public static int NumberOfSomething { get; set; }
public static string MangleString( string someValue )
{
}
}
当你有一个普通的有状态的类时,单例是最有用的,但你只想要其中一个。其他人提供的链接对于探索单例模式应该很有用。
Singleton != Global
. 您似乎在寻找关键字static
。
只有当这两个条件都为真时,单例才有意义:
- 对象必须是全局的
- 必须只存在一个对象的实例
请注意,#2 并不意味着您希望对象只有一个实例——如果是这样,只需实例化一次——这意味着必须存在(如,这不正确是很危险的)只能是一个实例。
如果您想要全局,只需创建某个(非符号)对象的全局实例(或使其成为静态或其他)。如果您只想要一个实例,那么静态是您的朋友。此外,只需实例化一个对象。
反正这是我的意见。
您可以真正简化单例实现,这就是我使用的:
internal FooService() { }
static FooService() { }
private static readonly FooService _instance = new FooService();
public static FooService Instance
{
get { return _instance; }
}
嗯,这一切似乎有点复杂。
为什么需要依赖注入框架来获取单例?对于某些企业应用程序来说,使用 IOC 容器是可以的(当然,只要它没有被过度使用),但是,啊,这家伙只是想知道如何实现该模式。
为什么不总是急切地实例化,然后提供一个返回静态的方法,上面写的大部分代码然后就消失了。遵循古老的 C2 格言 - DoTheSimplestThingThatCouldPossiblyWork...
我建议您阅读MSDN 上提供的Exploring the Singleton Design Pattern文章。它详细介绍了使模式易于实现的框架的特性。
顺便说一句,我会查看SO 有关 Singletons 的相关阅读。
忽略你是否应该使用单例模式的问题,这已经在别处讨论过,我会像这样实现一个单例:
/// <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() {
}
}
如果您想要松散耦合的设计,静态单例几乎是一种反模式。尽可能避免,除非这是一个非常简单的系统,否则我建议您查看许多可用的依赖注入框架之一,例如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>();
顺便说一句,公认的答案是一个糟糕的解决方案,至少检查实际实施该模式的人。
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); }
}
}
我喜欢这种模式,尽管它不会阻止某人创建非单例实例。有时,最好教育团队中的开发人员使用正确的方法,而不是竭尽全力防止某些笨蛋以错误的方式使用您的代码……
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() 之前不会调用静态构造函数。
您所描述的只是静态函数和常量,而不是单例。单例设计模式(很少需要)描述了一个实例化的类,但在第一次使用时自动实例化一次。
它将延迟初始化与检查结合起来,以防止多次实例化。它只对包装一些物理上单一的概念的类真正有用,例如围绕硬件设备的包装器。
静态常量和函数就是这样:根本不需要实例的代码。
问问自己这个问题:“如果有多个实例,这个类会中断吗?” 如果答案是否定的,则不需要单例。
嗯...很少有具有相关功能的常量...通过枚举不是更好吗?我知道您可以使用方法和所有方法在 Java 中创建自定义枚举,在 C# 中也应该可以实现,如果不直接支持,那么可以使用带有私有构造函数的简单类单例来完成。
如果您的常量在语义上相关,您应该考虑枚举(或等效概念),您将获得 const 静态变量的所有优势 + 您将能够利用编译器的类型检查来发挥您的优势。
我的 2 美分
就我个人而言,我会选择一个依赖注入框架,比如 Unity,它们都能够在容器中配置单例项,并通过从类依赖转移到接口依赖来改善耦合。
通过隐藏公共构造函数,添加一个私有静态字段来保存这个唯一的实例,并添加一个静态工厂方法(带有惰性初始化器)来返回那个单一的实例
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();
}
}
我使用单例模式为我的项目编写了一个类。这是非常容易使用。希望它对你有用。请找到以下代码。
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();
}
在 c# 中它可能是(线程安全以及延迟初始化):
public sealed class MySingleton
{
static volatile Lazy<MySingleton> _instance = new Lazy<MySingleton>(() => new MySingleton(), true);
public static MySingleton Instance => _instance.Value;
private MySingleton() { }
}