Универсальный синглтон - PullRequest
19 голосов
/ 19 декабря 2008

Что вы, ребята, думаете об этом для универсального синглтона?

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);
            }
        }
    }
}

Ответы [ 7 ]

30 голосов
/ 19 декабря 2008

Создание одноэлементного класса - это всего лишь несколько строк кода, и с трудностями создания общего синглтона я всегда пишу эти строки кода.

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

private static Singleton _instance = new Singleton();
Строка

устраняет необходимость в блокировке, так как статический конструктор является поточно-ориентированным.

5 голосов
/ 25 октября 2011

Это моя точка зрения с использованием .NET 4

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; } } 
    }

и использует следующее:

   public class Adaptor
   {
     public static Adaptor Instance { get { return Singleton<Adaptor>.Instance;}}
   }
5 голосов
/ 19 декабря 2008

Я удалил свой предыдущий ответ, так как я не заметил код, который проверяет непубличные конструкторы. Однако, это проверка, которая выполняется только во время выполнения - нет проверки время компиляции , которая является ударом по ней. Он также зависит от наличия достаточного доступа для вызова непубличного конструктора, что добавляет некоторые ограничения.

Кроме того, он не запрещает внутренние конструкторы - так что вы можете получить не синглетоны.

Я бы лично создал экземпляр в статическом конструкторе для обеспечения безопасности простых потоков.

По сути, я не большой поклонник - довольно просто создавать синглтон-классы, и в любом случае вам не следует делать это так часто. Синглтоны - это боль для испытаний, развязки и т. Д.

5 голосов
/ 19 декабря 2008

Ну, на самом деле это не синглтон - поскольку вы не можете контролировать T, может быть столько экземпляров T, сколько вам нужно.

(удалено состязание нитей; отмечено двойное использование)

1 голос
/ 20 марта 2013

Слияние ответа AndreasN и « Четвертой версии» Джона Скита - не совсем ленивое, но поточно-ориентированное без использования блокировок »реализации Singleton 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>

Затем вы можете сохранить это в файл .snippt и добавить его в VS IDE (Инструменты-> Диспетчер фрагментов кода)

0 голосов
/ 26 ноября 2016

Существует проблема с универсальной одноэлементной фабрикой, поскольку она универсальная, вы не управляете экземпляром типа singleton, который создается, поэтому вы не можете никогда не гарантировать , что созданный вами экземпляр будет единственный экземпляр в приложении.

Итак, вы не можете создать универсальную фабрику синглтона - это подрывает сам шаблон.

0 голосов
/ 17 августа 2016

Я не думаю, что использование дженериков полезно для одиночек. Потому что вы всегда можете создать несколько экземпляров, и поэтому по определению это , а не . Если вам нужен ленивый синглтон и вы хотите, чтобы он был настоящим синглтоном, простое решение (на примере Александра)

public sealed class Adaptor
{
    private static readonly Lazy<Adaptor> instance = new Lazy<Adaptor>(() => new Adaptor());

    public static Adaptor Instance { get { return instance.Value; } }

    private Adaptor() { }
}

Вы не можете должным образом преобразовать это в отдельный общий синглтон.

Смотри также: http://csharpindepth.com/Articles/General/Singleton.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...