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?

amutha
fonte
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() {}
}
Jon Skeet
fonte
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.

atlaste
fonte
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