Подтвердить что ты не робот

Общий синглтон

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

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

Ответ 1

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

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();
Строка

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

Ответ 2

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

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

Ответ 3

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

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

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

В принципе, я не поклонник - довольно легко создавать одноэлементные классы, и вы не должны так часто это делать. Синглтоны - это боль для тестирования, развязки и т.д.

Ответ 4

Это моя точка, использующая .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

Объединение ответа AndreasN и Jon Skeet " Четвертая версия - не такая ленивая, но потокобезопасная без использования блокировок" реализации Singleton С#, почему бы не использовать фрагмент кода для выполнения всей тяжелой работы:

<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 (Tools- > Code Snippets Manager)

Ответ 6

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

Итак, вы не можете создать общий синглтон factory - он подрывает сам шаблон.

Ответ 7

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

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