Padrão Singleton para C# [fechado]

Preciso de armazenar um monte de variáveis que precisam de ser acedidas globalmente e pergunto-me se um padrão singleton seria aplicável. Pelos exemplos que vi, um padrão singleton é apenas uma classe estática que não pode ser herdada. Mas os exemplos que vi são demasiado complexos para as minhas necessidades. Qual seria a classe singleton mais simples? Não podia fazer uma aula estática e selada com algumas variáveis lá dentro?

Author: cam, 2010-04-19

8 answers

Tipicamente um singleton não é Uma classe estática - um singleton dar-lhe-á uma única instância de uma classe.

Não sei que exemplos você viu, mas normalmente o padrão de singleton pode ser muito simples em C#:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    static Singleton() {} // Make sure it's truly lazy
    private Singleton() {} // Prevent instantiation outside

    public static Singleton Instance { get { return instance; } }
}
Isso não é difícil. A vantagem de um singleton sobre os membros estáticos é que a classe pode implementar interfaces, etc. Às vezes isso é útil - mas outras vezes, membros estáticos realmente faria bem. Além disso, é geralmente mais fácil passar de um singleton para um não-singleton mais tarde, por exemplo, passando no singleton como um objeto de "configuração" para classes de dependência, em vez daquelas classes de dependência que fazem chamadas estáticas diretas. Pessoalmente, tentaria evitar usar singletons sempre que possível, tornando os testes mais difíceis, além de qualquer outra coisa. Podem ocasionalmente ser úteis.
 35
Author: Jon Skeet, 2018-09-04 21:07:39
Há vários padrões que podem ser apropriados para ti, um singleton é um dos piores.

Registo

struct Data {
  public String ProgramName;
  public String Parameters;
}

class FooRegistry {
  private static Dictionary<String, Data> registry = new Dictionary<String, Data>();
  public static void Register(String key, Data data) {
     FooRegistry.registry[key] = data;
  }
  public static void Get(String key) {
     // Omitted: Check if key exists
     return FooRegistry.registry[key];
  }
}

Vantagens

    É fácil mudar para um objecto falso para testes automáticos.
  • você ainda pode armazenar várias instâncias, mas se necessário você tem apenas uma instância.

Desvantagens

  • ligeiramente mais lento do que um Singleton ou uma variável global

Estática Classe

class GlobalStuff {
  public static String ProgramName {get;set;}
  public static String Parameters {get;set;}
  private GlobalStuff() {}
}

Vantagens

  • simples
  • Rápido

Desvantagens

    É difícil mudar dinamicamente para um objecto falso.
  • difícil mudar para outro tipo de objecto se os requisitos mudarem

Singleton Simple

class DataSingleton {
  private static DataSingleton instance = null;
  private DataSingleton() {}
  public static DataSingleton Instance {
     get {
         if (DataSingleton.instance == null) DataSingleton.instance = new DataSingleton();
         return DataSingleton;
     }
  }
}

Vantagens

  • Nenhum realmente

Desvantagens

    É difícil criar uma threadsafe singleton., a versão acima irá falhar se vários tópicos acederem à instância.
  • é difícil mudar para um objecto falso
Pessoalmente, gosto do padrão de Registo, mas MMMV.

Você deve dar uma olhada na injeção de dependência como geralmente é considerada a melhor prática, mas é um tópico muito grande para explicar aqui:

Injecção De Dependência

 8
Author: Morfildur, 2018-04-12 15:15:47
Um Singleton não é apenas uma classe estática que não pode ser herdada. É uma classe regular que só pode ser instanciada uma vez, com todos compartilhando essa instância única (e torná-la segura é ainda mais trabalho). O típico código. NET para um Singleton parece-se com o seguinte. Este é um exemplo rápido, e não de forma alguma o melhor código de implementação ou thread-safe:
public sealed class Singleton
{
    Singleton _instance = null;

    public Singleton Instance
    {
        get
        {
            if(_instance == null)
                _instance = new Singleton();

            return _instance;
        }
    }

    // Default private constructor so only we can instanctiate
    private Singleton() { }

    // Default private static constructor
    private static Singleton() { }
}
Se vais seguir o caminho que estás a pensar, uma estática selada a aula vai funcionar bem.
 3
Author: Justin Niessner, 2010-04-19 12:41:46

Usando Inicializadores De Propriedade Automática C# 6.

public sealed class Singleton
{
    private Singleton() { }
    public static Singleton Instance { get; } = new Singleton();
}
Curto e limpo, ficarei feliz em ouvir as desvantagens.
 1
Author: chenop, 2016-10-30 13:35:34

Eu sei que este problema é antigo, mas aqui está outra solução usando. Net 4.0 ou mais tarde (incluindo.Net Core e .net Standard).

Primeiro, define a tua classe que será transformada num Singleton.
public class ClassThatWillBeASingleton
{
    private ClassThatWillBeASingleton()
    {
        Thread.Sleep(20);
        guid = Guid.NewGuid();
        Thread.Sleep(20);
    }

    public Guid guid { get; set; }
}
Nesta classe de exemplo, defini um construtor que dorme durante algum tempo, e depois cria um novo Guid e guarda para a sua propriedade pública. (O sono é apenas para testes de concorrência) Repare que o construtor é privado, para que ninguém possa criar um um novo exemplo desta turma. Temos de definir o invólucro que transformará esta classe num singleton.
public abstract class SingletonBase<T> where T : class
{
    private static readonly Lazy<T> _Lazy = new Lazy<T>(() =>
    {
        // Get non-public constructors for T.
        var ctors = typeof(T).GetConstructors(System.Reflection.BindingFlags.Instance |
                                              System.Reflection.BindingFlags.NonPublic);
        if (!Array.Exists(ctors, (ci) => ci.GetParameters().Length == 0))
            throw new InvalidOperationException("Non-public ctor() was not found.");
        var ctor = Array.Find(ctors, (ci) => ci.GetParameters().Length == 0);
        // Invoke constructor and return resulting object.
        return ctor.Invoke(new object[] { }) as T;
    }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);

    public static T Instance
    {
        get { return _Lazy.Value; }
    }
}

Repare que ele usa a preguiça para criar um campo _Lazy que sabe como instanciar uma classe usando o seu construtor privado.

E define uma propriedade Instance para aceder ao valor do campo preguiçoso.

Reparem no enum que é passado ao construtor preguiçoso. Está a usar ExecutionAndPublication. Assim, apenas um tópico será permitido inicializar o Valor do campo preguiçoso. Agora, tudo o que temos de fazer é definir a classe embrulhada que será uma singleton:
public class ExampleSingleton : SingletonBase<ClassThatWillBeASingleton>
{
    private ExampleSingleton () { }
}

Aqui está um exemplo do uso:

ExampleSingleton.Instance.guid;
E um teste para afirmar que dois fios terão a mesma instância do Singleton:
[Fact()]
public void Instance_ParallelGuid_ExpectedReturnSameGuid()
{
    Guid firstGuid = Guid.Empty;
    Guid secondGuid = Guid.NewGuid();

    Parallel.Invoke(() =>
    {
        firstGuid = Singleton4Tests.Instance.guid;
    }, () =>
    {
        secondGuid = Singleton4Tests.Instance.guid;
    });

    Assert.Equal(firstGuid, secondGuid);
}
Este teste está chamando o valor do campo preguiçoso simultaneamente, e queremos afirmar que ambas as instâncias que serão devolvidas desta propriedade (valor de preguiçoso) são as mesmas.

Mais detalhes sobre este assunto pode ser encontrado em: C# em profundidade

 0
Author: Rodrigo Riskalla Leal, 2018-04-10 15:45:03
Então, no que me diz respeito, esta é a implementação mais concisa e simples do padrão Singleton em C#.

Http://blueonionsoftware.com/blog.aspx?p=c6e72c38-2839-4696-990a-3fbf9b2b0ba4

No entanto, sugiro que os singletons são padrões muito feios... Considero-os um anti-padrão.

Http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

Para mim, prefiro ter algo como ... Repositório, implementando IRepository. A sua classe pode declarar a dependência do IRepository no construtor e pode ser aprovada através de uma injecção de dependência ou de um destes métodos:

Http://houseofbilz.com/archive/2009/05/02.aspx

 -1
Author: Brian Genisio, 2010-04-19 11:49:10

Usa as tuas características linguísticas. A implementação mais simples de thread-safe é:

public sealed class Singleton
{
    private static readonly Singleton _instance;

    private Singleton() { }

    static Singleton()
    {
        _instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return _instance; }
    }
}
 -1
Author: ZOXEXIVO, 2016-08-10 20:34:03

...qual seria a classe singleton mais simples?

Só para adicionar mais uma solução possível. A abordagem mais simples, mais direta e fácil de usar que eu possa pensar seria algo assim:

//The abstract singleton
public abstract class Singleton<T> where T : class
{
    private static readonly Lazy<T> instance = new Lazy<T>( CreateInstance, true );

    public static T Instance => instance.Value;

    private static T CreateInstance()
    {
        return (T)Activator.CreateInstance( typeof(T), true);
    }
}

//This is the usage for any class, that should be a singleton
public class MyClass : Singleton<MyClass>
{
    private MyClass()
    {
        //Code...
    }

    //Code...
}

//Example usage of the Singleton
class Program
{
    static void Main(string[] args)
    {
        MyClass clazz = MyClass.Instance;
    }
}
 -1
Author: Nate Stone, 2018-04-11 17:43:31