Singleton por Jon Skeet esclarecimentos


214
public sealed class Singleton
{
    Singleton() {}

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

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}
        internal static readonly Singleton instance = new Singleton();
    }
}

Desejo implementar o padrão Singleton de Jon Skeet em meu aplicativo atual em C #.

Eu tenho duas duvidas no código

  1. Como é possível acessar a classe externa dentro da classe aninhada? Quero dizer

    internal static readonly Singleton instance = new Singleton();

    É algo chamado fechamento?

  2. Não consigo entender este comentário

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    

    o que esse comentário nos sugere?


12
haha eu pensei que eu tinha dito que estava um pouco preocupado lol ... acabou por ser uma pessoa diferente John Nolan
— John Antony Daniel Nolan

14
Duas coisas são universalmente aceitas: o sol nasce do leste e Jon Skeet está sempre certo. Mas ainda não tenho certeza sobre o primeiro: P
— akhil_mittal

2
@ thepirat000 - Se ele fosse apenas um participante do SO / Meta, eu poderia discordar, mas ele tem influência suficiente no mundo real da programação para que isso possa realmente ser legítimo - eu tenho certeza que alguém o criou em um ponto ou outro .
— Code Jockey

8
A taxonomia desta pergunta está sendo discutida no meta .
— BoltClock

Respostas:


359
  1. Não, isso não tem nada a ver com fechamentos. Uma classe aninhada tem acesso aos membros privados de sua classe externa, incluindo o construtor privado aqui.

  2. Leia o meu artigo no beforefieldinit . Você pode ou não querer o construtor estático não operacional - isso depende da preguiça que você precisa. Você deve estar ciente de que o .NET 4 altera um pouco a semântica de inicialização de tipo real (ainda dentro da especificação, mas mais preguiçoso do que antes).

Você realmente precisa desse padrão? Tem certeza de que não pode se safar:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}

12
@ Anindya: Não, tudo bem. Você pode querer JetBrains e-mail para reclamar embora :)
— Jon Skeet

2
@ JonSkeet, acabei de levantar uma preocupação para o JetBrains sobre isso (# RSRP-274373). Vamos ver o que eles podem criar. :)
— Anindya Chatterjee

3
@ Lua: Você não. Um singleton vive pela duração do AppDomain.
— Jon Skeet

2
@ JonSkeet Alguma razão para não usar Lazy<T>para que você não precise declarar um construtor estático para o BeforeFieldInitefeito colateral mágico ?
— Ed T

3
FieldBeforeInité MahaBharatadeMicrosoft
— Amit Kumar Ghosh

49

Em relação à pergunta (1): A resposta de Jon está correta, pois ele marca implicitamente a classe 'Nested' como privada, não a tornando pública ou interna :-). Você pode fazê-lo explicitamente adicionando 'private':

    private class Nested

Em relação à pergunta (2): basicamente, o que a postagem sobre beforeinitfield e a inicialização de tipo dizem é que, se você não tiver um construtor estático, o tempo de execução poderá inicializá-lo a qualquer momento (mas antes de usá-lo). Se você tiver um construtor estático, seu código no construtor estático poderá inicializar os campos, o que significa que o tempo de execução só pode inicializar o campo quando você solicitar o tipo.

Portanto, se você não deseja que o tempo de execução inicialize os campos 'proativamente' antes de usá-los, adicione um construtor estático.

De qualquer maneira, se você estiver implementando singletons, deseja que ele seja inicializado o mais preguiçosamente possível e não quando o tempo de execução achar que deve inicializar sua variável - ou você provavelmente não se importa. Da sua pergunta, suponho que você os queira o mais tarde possível.

Isso leva ao post de Jon sobre o singleton , que é o tópico subjacente desta pergunta na IMO. Ah e as dúvidas :-)

Eu gostaria de salientar que o singleton # 3, que ele marcou como 'errado', está realmente correto (porque o lock's implica automaticamente uma barreira de memória na saída ). Também deve ser mais rápido que o singleton nº 2 quando você usa a instância mais de uma vez (que é mais ou menos o ponto de um singleton :-)). Portanto, se você realmente precisa de uma implementação preguiçosa de singleton, eu provavelmente optaria por essa - pelas simples razões de que (1) é muito claro para todos que lêem seu código o que está acontecendo e (2) você sabe o que acontecerá com exceções.

Caso você esteja se perguntando: eu nunca usaria o singleton nº 6 porque pode facilmente levar a conflitos e comportamento inesperado, com exceções. Para obter detalhes, consulte: modo de bloqueio do preguiçoso , especificamente ExecutionAndPublication.


62
Regarding question (1): The answer from Jon is correct ...Jon Skeet está sempre correto ....
— Noctis 12/11

72
Pontos extras por tentar responder a uma pergunta de Jon Skeet na qual Jon Skeet já respondeu.
— Valdetero 11/05

8
@valdetero Hahaha. Isso ... hahaha +1
— akinuri
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.