Singleton por esclarecimento de Jon Skeet

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 no meu aplicativo atual em C #.

Eu tenho duas dúvidas sobre o código

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

     internal static readonly Singleton instance = new Singleton(); 

    É algo chamado fechamento?

  2. Eu não consigo entender esse comentário

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

    o que esse comentário nos sugere?

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

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

Você realmente precisa desse padrão? Tem certeza de que você 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() {} } 

Em relação à questão (1): A resposta de Jon está correta, pois ele implicitamente marca a class ‘Aninhada’ privada por não torná-la pública ou interna :-). Você pode fazê-lo explicitamente adicionando ‘private’:

  private class Nested 

Em relação à questão (2): basicamente o que o post sobre beforeinitfield e type initialization lhe dizem é que se você não tiver nenhum construtor estático, o runtime pode 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ó tem permissão para inicializar o campo quando você solicita o tipo.

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

De qualquer maneira, se você está implementando singletons, você quer que ele seja inicializado o mais preguiçoso possível e não quando o tempo de execução acha que deve inicializar sua variável – ou você provavelmente não se importa. De sua pergunta, suponho que você os queira o mais tarde possível.

Isso traz o encontro para o post de Jon sobre singleton ‘s, que é o tema subjacente desta questão. Ah e as duvidas 🙂

Eu gostaria de salientar que seu singleton # 3, que ele marcou “errado”, está correto (porque o bloqueio implica automaticamente uma barreira de memory na saída ). Ele também deve ser mais rápido que o singleton # 2 quando você usa a instância mais de uma vez (que é mais ou menos o ponto de um singleton :-)). Então, se você realmente precisa de uma implementação preguiçosa de singletons, eu provavelmente escolheria essa – pelas simples razões que (1) é muito claro para todos que lêem o seu código o que está acontecendo e (2) você sabe o que vai acontecer com exceções.

Caso você esteja se perguntando: eu nunca usaria singleton # 6 porque ele pode facilmente levar a deadlocks e comportamentos inesperados com exceções. Para mais detalhes, consulte: modo de bloqueio do lazy , especificamente ExecutionAndPublication.