O que é um singleton em c #?


182

O que é um Singleton e quando devo usá-lo?



4
Além disso, o Singleton é um dos padrões de design mais utilizados e abusados ​​na programação OO.
precisa saber é o seguinte

3
@Fabiano: Porque ele tem uma maneira de criar acoplamentos que não fazem sentido (como posso Xconversar Y? Basta criar Yum singleton!), O que, por sua vez, leva a dificuldades para testar / depurar e a um estilo processual de programação. Às vezes Singletons são necessários; na maioria das vezes, não.
Aaronaught 28/01

3
Esta é uma das minhas perguntas padrão da entrevista por telefone. A resposta correta é: nunca.
jonnii

3
@ Jonnii isso é bom, ajuda a alertar os desenvolvedores em potencial como é o chefe!
Mr. Boy

Respostas:


145

Um singleton é uma classe que permite apenas que uma instância seja criada - e fornece acesso simples e fácil a essa instância. A premissa singleton é um padrão no desenvolvimento de software.

Há uma implementação em C # "Implementando o Padrão Singleton em C #", cobrindo a maior parte do que você precisa saber - incluindo alguns bons conselhos sobre segurança de threads .

Para ser honesto, é muito raro você precisar implementar um singleton - na minha opinião, deve ser uma daquelas coisas que você deve estar ciente, mesmo que não seja usado com muita frequência.


2
bom tutorial, mas caramba, o que eles fizeram com o recuo do código?
Inspi 19/01

Aqui está um link mais direto para o que considero a implementação ideal em 2020. Ou seja, " usando o tipo Lazy <T> do .NET 4 ", bem como o link para o Microsoft Doc Lazy<T> Class.
Chiramisu 20/02

52

Você pediu c #. Exemplo trivial:


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
Não thread thread safe.two thread pode chamar ao mesmo tempo e pode criar dois objetos separados.
Alagesan Palani

5
@ Alagesan Palani, na verdade você está certo. Não sou proficiente nos detalhes de baixo nível da inicialização em nível de classe, mas acho que a alteração que fiz abordou a preocupação de segurança de threads.
Chris Simmons

3
Claro, eu não estou apontando que você está errado. estou dando uma dica ao leitor sobre segurança de threads, para que eles tomem cuidado se precisarem lidar com isso.
Alagesan Palani

9
Não, acho que seu comentário é importante. Dado que um singleton deve entregar uma - e apenas uma - instância, a condição de corrida aqui abre a possibilidade de que mais de uma seja entregue. Veja a versão agora, com inicialização de campo estático. Acredito que isso resolva o problema de segurança do thread, se eu ler os documentos e esta resposta SO corretamente.
Chris Simmons

1
@AlagesanPalani, vejo que você declarou que várias outras respostas não são seguras para discussão. Você gostaria de fornecer uma solução segura para threads?
precisa saber é o seguinte

39

O que é: Uma classe para a qual existe apenas uma instância persistente durante a vida útil de um aplicativo. Veja Padrão Singleton .

Quando você deve usá-lo: o mínimo possível. Somente quando você estiver absolutamente certo de que precisa. Estou relutante em dizer "nunca", mas geralmente há uma alternativa melhor, como injeção de dependência ou simplesmente uma classe estática.


16
Não tenho certeza de que uma classe estática seja uma alternativa melhor do que um singleton ... realmente depende da situação e do idioma.
marcgg

5
Classes estáticas não se comportam da mesma maneira que um singleton, um singleton pode ser passado para métodos como um parâmetro, enquanto uma classe estática não pode.
usar o seguinte código

4
Concordo com o marcgg - não vejo uma classe estática como uma boa alternativa aos singletons, porque você ainda tem o problema de fornecer um substituto, por exemplo, durante o teste de um componente que depende dessa classe. Mas também vejo usos diferentes; uma classe estática normalmente seria usada para funções utilitárias independentes que são independentes do estado, em que um singleton é uma instância de classe real e, normalmente, armazenava um estado. Concordo totalmente em usar o DI e, em seguida, diga ao seu contêiner de DI que você deseja que ele use apenas uma única instância dessa classe.
Pete

9
Eu diminuí a votação desta resposta porque ela não fornece informações sobre quando usá-la. "Somente quando você precisar" não me fornece realmente nenhuma informação para alguém que é novo nos singletons.
Sergio Tapia

9
@Adkins: DI significa Injeção de Dependência, que é quando qualquer dependência de classe é passada através (geralmente) de um construtor ou propriedade pública. A DI sozinha não resolve o problema da "distância", mas geralmente é implementada juntamente com um contêiner de Inversão de Controle (IoC) que sabe como inicializar automaticamente quaisquer dependências. Portanto, se você estiver criando um Singleton para resolver o problema "X não sabe como encontrar / falar com Y", uma combinação de DI e IoC poderá resolver o mesmo problema com o acoplamento mais flexível.
Aaronaught

27

outra maneira de implementar singleton em c #, eu pessoalmente prefiro esse caminho, porque você pode acessar a instância da classe singeton como uma propriedade em vez de um método.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }

mas, tanto quanto eu sei, os dois lados são considerados "certos", por isso é apenas algo pessoal.


11
Não thread thread safe.two thread pode chamar ao mesmo tempo e pode criar dois objetos separados.
Alagesan Palani

11
using System;
using System.Collections.Generic;
class MainApp
{
    static void Main()
    {
        LoadBalancer oldbalancer = null;
        for (int i = 0; i < 15; i++)
        {
            LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();

            if (oldbalancer == balancerNew && oldbalancer != null)
            {
                Console.WriteLine("{0} SameInstance {1}", oldbalancer.Server, balancerNew.Server);
            }
            oldbalancer = balancerNew;
        }
        Console.ReadKey();
    }
}

class LoadBalancer
{
    private static LoadBalancer _instance;
    private List<string> _servers = new List<string>();
    private Random _random = new Random();

    private static object syncLock = new object();

    private LoadBalancer()
    {
        _servers.Add("ServerI");
        _servers.Add("ServerII");
        _servers.Add("ServerIII");
        _servers.Add("ServerIV");
        _servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
        if (_instance == null)
        {
            lock (syncLock)
            {
                if (_instance == null)
                {
                    _instance = new LoadBalancer();
                }
            }
        }

        return _instance;
    }

    public string Server
    {
        get
        {
            int r = _random.Next(_servers.Count);
            return _servers[r].ToString();
        }
    }
}

Peguei o código do dofactory.com , nada tão chique, mas acho isso muito bom do que exemplos com Foo e Bar. Além disso, livro de Judith Bishop no C # 3.0 Design Patterns tem exemplo sobre aplicativos ativos no mac dock.

Se você observar o código, na verdade, estamos construindo novos objetos no loop for , de modo que cria um novo objeto, mas reutiliza a instância como resultado da qual o oldbalancer e o newbalancer têm a mesma instância, como? devido à palavra-chave estática usada na função GetLoadBalancer () , apesar de ter um valor diferente do servidor, que é uma lista aleatória, a estática em GetLoadBalancer () pertence ao próprio tipo e não a um objeto específico.

Além disso, há bloqueio de verificação dupla aqui

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

desde do MSDN

A palavra-chave lock garante que um segmento não insira uma seção crítica do código enquanto outro segmento está na seção crítica. Se outro encadeamento tentar inserir um código bloqueado, ele aguardará, bloqueado, até que o objeto seja liberado.

portanto, sempre é emitido um bloqueio de exclusão mútua, mesmo que não seja necessário o que é desnecessário, para que tenhamos uma verificação nula.

Espero que ajude a esclarecer mais.

E, por favor, comente se eu entendo que estou direcionando caminhos errados.


6

Um Singleton (e isso não está vinculado ao C #, é um padrão de design OO) é quando você deseja permitir que apenas uma instância de uma classe seja criada em todo o aplicativo. Useages normalmente inclui recursos globais, embora eu diria por experiência pessoal, eles são muitas vezes a fonte de muita dor.


5

Embora a única instância de um singleton possa existir apenas, ela não é a mesma que uma classe estática. Uma classe estática pode conter apenas métodos estáticos e nunca pode ser instanciada, enquanto a instância de um singleton pode ser usada da mesma maneira que qualquer outro objeto.


2

É um padrão de design e não é específico para c #. Mais sobre isso em toda a Internet e SO, como neste artigo da Wikipedia .

Na engenharia de software, o padrão singleton é um padrão de design usado para restringir a instanciação de uma classe a um objeto. Isso é útil quando exatamente um objeto é necessário para coordenar ações no sistema. Às vezes, o conceito é generalizado para sistemas que operam com mais eficiência quando existe apenas um objeto ou que restringem a instanciação a um determinado número de objetos (digamos, cinco). Alguns consideram um antipadrão, julgando que é usado em excesso, introduz limitações desnecessárias em situações em que uma única instância de uma classe não é realmente necessária e introduz um estado global em um aplicativo.

Você deve usá-lo se quiser uma classe que só pode ser instanciada uma vez.


2

Eu o uso para dados de pesquisa. Carregue uma vez do DB.

public sealed class APILookup
    {
        private static readonly APILookup _instance = new APILookup();
        private Dictionary<string, int> _lookup;

        private APILookup()
        {
            try
            {
                _lookup = Utility.GetLookup();
            }
            catch { }
        }

        static APILookup()
        {            
        }

        public static APILookup Instance
        {
            get
            {
                return _instance;
            }
        }
        public Dictionary<string, int> GetLookup()
        {
            return _lookup;
        }

    }

2

O que é um singleton:
é uma classe que permite apenas que uma instância seja criada e geralmente fornece acesso simples a essa instância.

Quando você deve usar:
Depende da situação.

Nota: não use na conexão db; para obter uma resposta detalhada, consulte a resposta de @Chad Grant

Aqui está um exemplo simples de um Singleton:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

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

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

Você também pode usar Lazy<T>para criar o seu Singleton.

Veja aqui um exemplo mais detalhado usandoLazy<T>


1

Aqui está o que singleton é: http://en.wikipedia.org/wiki/Singleton_pattern

Eu não sei c #, mas na verdade é a mesma coisa em todos os idiomas, apenas a implementação difere.

Geralmente, você deve evitar o singleton quando possível, mas em algumas situações é muito conveniente.

Desculpe pelo meu Inglês ;)


o seu Inglês é :) OK
FrenkyB

1

A classe Singleton é usada para criar uma única instância para todo o domínio do aplicativo.

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    public static Singleton Instance
    {
        get { return singletonInstance; }            
    }
}

No presente artigo, é descrito como podemos criar rosca única classe segura usando somente leitura variável e seu uso prático nas aplicações.


1

Sei que é muito tarde para responder à pergunta, mas com a propriedade automática, você pode fazer algo assim:

public static Singleton Instance { get; } = new Singleton();

Onde Singletonestá sua classe e pode ser via, neste caso, a propriedade readonly Instance.


0

EX Você pode usar o Singleton para obter informações globais que precisam ser injetadas.

No meu caso, eu mantinha os detalhes do usuário registrado (nome de usuário, permissões etc.) na classe estática global. E quando tentei implementar o Teste de Unidade, não havia como injetar dependência nas classes Controller. Assim, mudei minha classe estática para o padrão Singleton.

public class SysManager
{
    private static readonly SysManager_instance = new SysManager();

    static SysManager() {}

    private SysManager(){}

    public static SysManager Instance
    {
        get {return _instance;}
    }
}

http://csharpindepth.com/Articles/General/Singleton.aspx#cctor


0

Precisamos usar o Singleton Design Pattern em C # quando precisamos garantir que apenas uma instância de uma classe específica seja criada e, em seguida, forneça acesso global simples a essa instância para todo o aplicativo.

Cenários em tempo real em que você pode usar o Padrão de Design Singleton: Proxies de Serviço: Como sabemos, invocar uma API de Serviço é uma operação extensa em um aplicativo. O processo que leva a maior parte do tempo é criar o cliente de serviço para chamar a API de serviço. Se você criar o proxy de serviço como Singleton, ele melhorará o desempenho do seu aplicativo.

Fachadas: você também pode criar as conexões do banco de dados como Singleton, o que pode melhorar o desempenho do aplicativo.

Logs: em um aplicativo, executar a operação de E / S em um arquivo é uma operação cara. Se você criar seu Logger como Singleton, ele melhorará o desempenho da operação de E / S.

Compartilhamento de dados: se você tiver valores constantes ou valores de configuração, poderá mantê-los em Singleton, para que possam ser lidos por outros componentes do aplicativo.

Armazenamento em cache: como sabemos, buscar os dados de um banco de dados é um processo demorado. No seu aplicativo, você pode armazenar em cache o mestre e a configuração na memória, o que evitará as chamadas ao banco de dados. Nessas situações, a classe Singleton pode ser usada para manipular o cache com sincronização de threads de maneira eficiente, o que melhora drasticamente o desempenho do aplicativo.

Desvantagens do Singleton Design Pattern em C # As desvantagens do uso do Singleton Design Pattern em C # são as seguintes:

O teste de unidade é muito difícil porque introduz um estado global em um aplicativo. Isso reduz o potencial de paralelismo em um programa porque, para acessar a instância singleton em um ambiente multithread, você precisa serializar o objeto usando o bloqueio.

Eu peguei isso no seguinte artigo.

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

Segure o Singleton seguro sem usar bloqueios e nenhuma instancia lenta.

Esta implementação possui um construtor estático, sendo executada apenas uma vez por Domínio do Aplicativo.

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

    public static Singleton Instance { get; } = new Singleton();

}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.