Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一般的单例_C#_Singleton_Generics - Fatal编程技术网

C# 一般的单例

C# 一般的单例,c#,singleton,generics,C#,Singleton,Generics,你们对一般的单身汉怎么看 using System; using System.Reflection; // Use like this /* public class Highlander : Singleton<Highlander> { private Highlander() { Console.WriteLine("There can be only one..."); } } */ public class Singleton&

你们对一般的单身汉怎么看

using System;
using System.Reflection;

// Use like this
/*
public class Highlander : Singleton<Highlander>
{
    private Highlander()
    {
        Console.WriteLine("There can be only one...");
    }
}
*/

public class Singleton<T> where T : class
{
    private static T instance;
    private static object initLock = new object();

    public static T GetInstance()
    {
        if (instance == null)
        {
            CreateInstance();
        }

        return instance;
    }

    private static void CreateInstance()
    {
        lock (initLock)
        {
            if (instance == null)
            {
                Type t = typeof(T);

                // Ensure there are no public constructors...
                ConstructorInfo[] ctors = t.GetConstructors();
                if (ctors.Length > 0)
                {
                   throw new InvalidOperationException(String.Format("{0} has at least one accesible ctor making it impossible to enforce singleton behaviour", t.Name));
                }

                // Create an instance via the private constructor
                instance = (T)Activator.CreateInstance(t, true);
            }
        }
    }
}
使用系统;
运用系统反思;
//像这样使用
/*
公务舱高地人:单身汉
{
私人高地人()
{
Console.WriteLine(“只能有一个…”);
}
}
*/
公共类单例,其中T:class
{
私有静态T实例;
私有静态对象initLock=新对象();
公共静态GetInstance()
{
if(实例==null)
{
CreateInstance();
}
返回实例;
}
私有静态void CreateInstance()
{
锁(initLock)
{
if(实例==null)
{
类型t=类型(t);
//确保没有公共构造函数。。。
ConstructorInfo[]ctors=t.GetConstructors();
如果(ctors.Length>0)
{
抛出新的InvalidOperationException(String.Format(“{0}至少有一个可访问的构造函数,使得无法强制执行单例行为”,t.Name));
}
//通过私有构造函数创建实例
instance=(T)Activator.CreateInstance(T,true);
}
}
}
}

好吧,它不是真正的单例-因为您无法控制
t
,所以可以有任意多个
t
实例


(删除了线程争用;注意了双重检查的用法)

创建一个单例类只需要几行代码,而且由于创建通用单例的困难,我总是编写这些代码行

public class Singleton
{
    private Singleton() {}
    static Singleton() {}
    private static Singleton _instance = new Singleton();
    public static Singleton Instance { get { return _instance; }}
}


行消除了锁定的需要,因为静态构造函数是线程安全的。

我删除了我以前的答案,因为我没有注意到检查非公共构造函数的代码。然而,这是一个只在执行时执行的检查——没有编译时检查,这是对它的攻击。它还依赖于拥有足够的访问权限来调用非公共构造函数,这增加了一些限制

此外,它并不禁止内部构造函数-因此您可以使用非单例

我个人也会在静态构造函数中创建实例,以实现简单的线程安全


基本上,我不太喜欢创建单例类——创建单例类非常容易,无论如何,你不应该经常这样做。对于测试、解耦等来说,单例是一种痛苦。

这是我使用.NET4的观点

public class Singleton<T> where T : class, new()
    {
        Singleton (){}

        private static readonly Lazy<T> instance = new Lazy<T>(()=> new T());

        public static T Instance { get { return instance.Value; } } 
    }
公共类单例,其中T:class,new()
{
单态(){}
私有静态只读惰性实例=newlazy(()=>newt());
公共静态T实例{get{return Instance.Value;}}
}
它的用途如下:

   public class Adaptor
   {
     public static Adaptor Instance { get { return Singleton<Adaptor>.Instance;}}
   }
公共类适配器
{
公共静态适配器实例{get{return Singleton.Instance;}}
}

融合AndreasN answer和Jon Skeet的“单例c#实现”,为什么不使用代码片段来完成所有的艰苦工作:

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>Singleton Class</Title>
            <Author>TWSoft</Author>
            <Description>Generates a singleton class</Description>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
            <Keywords>
                <Keyword>Singleton</Keyword>
            </Keywords>
            <Shortcut>singleton</Shortcut>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>ClassName</ID>
                    <ToolTip>Replace with class name</ToolTip>
                    <Default>MySingletonClass</Default>
                </Literal>
            </Declarations>

            <Code Language="CSharp">
                <![CDATA[
                public class $ClassName$
                {
                    #region Singleton
                    static readonly $ClassName$ mInstance = new $ClassName$();

                    // Explicit static constructor to tell C# compiler
                    // not to mark type as beforefieldinit
                    static $ClassName$()
                    {
                    }

                    private $ClassName$()
                    {
                    }

                    public static $ClassName$ Instance
                    {
                        get { return mInstance; }
                    }
                #endregion
                }
                ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

独生子女班
TWSoft
生成一个单例类
膨胀
独生子女
独生子女
类名
替换为类名
MySingletonClass



然后您可以将其保存到.snippt文件中,并将其添加到VS IDE(工具->代码片段管理器)

使用泛型对单例无效。因为您总是可以创建类型参数T的多个实例,然后根据定义,它是而不是

看看这个:

public sealed class Singleton<T> where T : class, new()
{
    private static readonly Lazy<T> instance = new Lazy<T>(() => new T());
    public static T Instance => instance.Value;
    private Singleton() { }
}
将私有构造函数添加到适配器会破坏代码。 请注意,此适配器使用组合而不是继承。也就是说,它不是一个单身汉,它有一个单身汉。如果某个东西是单例的,它应该派生或实现一个接口

public abstract class Singleton<T> 
{
    protected static Lazy<T> instance;
    public static T Instance => instance.Value;
}

public sealed class Adapter : Singleton<Adapter>
{
    static Adapter()
    {
        instance = new Lazy<Adapter>(() => new Adapter());
    }

    private Adapter() { }
}

此类错误只能在测试期间检测到

我仍然更愿意直接使用模式,它基本上只有3行代码,而且编译时是安全的。另外,当您需要不同的基类,但仍然需要一个懒惰的单例,并要求它是一个真正的单例时,存在一个简单的解决方案:(请参阅:)

公共密封类适配器
{
私有静态只读惰性实例=新惰性(()=>新适配器());
公共静态适配器实例{get{return Instance.Value;}}
专用适配器(){}
}

您无法将其正确地重构为一个通用的单例,不能像上面研究的方法那样被误用。

完全正确。特别是当泛型版本实际上并没有给你一个单例时……你可能还应该添加一个静态构造函数。确实看到了。对于延迟加载,Jon的页面也用嵌套类覆盖了这一点。除非对锁定对象使用volatile关键字,否则这种锁定技术将被破坏。参见我在链接的Jon Skeet文章中添加了静态构造函数;在大多数情况下,静态类更合适。用于实现接口等,但标准模式工作良好,无需泛型。不要忘记链接…Jon!:)@肯尼:那个链接正是我需要的。谢谢除非对锁定对象使用volatile关键字,否则此锁定技术将被破坏。请参阅codereview.stackexchange.com的精细问题此方法的问题是它需要singleton实现类的公共构造函数,这允许在singleton实例的边界之外使用(即,这里不存在编译时预防)。这是其泛型的成本。是的,只是需要让noob明白,你应该给适配器添加一个私有构造函数,这会破坏你的设计。这是它的泛型的成本
public class Adapter
{
    public static Adapter Instance => Singleton<Adapter>.Instance; 
    // private Adapter(){ } // doesn't compile.
}
new Adapter();
public abstract class Singleton<T> 
{
    protected static Lazy<T> instance;
    public static T Instance => instance.Value;
}

public sealed class Adapter : Singleton<Adapter>
{
    static Adapter()
    {
        instance = new Lazy<Adapter>(() => new Adapter());
    }

    private Adapter() { }
}
public abstract class Singleton<T> where T : Singleton<T>, new()
{
    private static bool instantiated;
    private static readonly Lazy<T> instance = new Lazy<T>(() => new T());
    public static T Instance => instance.Value;
    protected Singleton()
    {
        if (instantiated)
            throw new Exception();
        instantiated = true;
    }
}

public /* sealed */ class Adapter : Singleton<Adapter>
{
}
  new Adapter(); // this works
  Adapter.Instance; // this throws an error.
  Adapter.Instance; // this works
  // just running in production someone decided to call:
  new Adapter(); // this throws an error
public sealed class Adapter
{
    private static readonly Lazy<Adapter> instance = new Lazy<Adapter>(() => new Adapter());
    public static Adapter Instance { get { return instance.Value; } }
    private Adapter() { }
}