2010-03-31 13 views
201
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(); 
    } 
} 

Deseo implementar Jon Skeet's Singleton pattern en mi aplicación actual en C#.Singleton por Jon Skeet aclaración

tengo dos dudas sobre el código

  1. ¿Cómo es posible acceder a la clase externa dentro de la clase anidada? Quiero decir

    internal static readonly Singleton instance = new Singleton(); 
    

    ¿Hay algo llamado cierre?

  2. Soy incapaz de entender este comentario

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

    ¿qué nos sugiere este comentario?

+11

jaja Pensé que había dicho que estaba un poco preocupado jaja ... resultó ser un John Nolan diferente –

+66

Así que al hacer una pregunta sobre el código de Jon Skeet, se obtienen 1000s de vistas y una respuesta del propio Skeet. –

+13

Dos cosas son universalmente aceptadas: el sol sale del este y Jon Skeet siempre tiene razón. Pero todavía no estoy seguro del anterior: P –

Respuesta

329
  1. No, esto no es nada que ver con cierres. Una clase anidada tiene acceso a los miembros privados de su clase externa, incluido el constructor privado aquí.

  2. Lea mi article on beforefieldinit. Puede o no querer el constructor estático no operativo, depende de las garantías de holgazanería que necesita. Debe tener en cuenta que .NET 4 changes the actual type initialization semantics somewhat (aún dentro de la especificación, pero más flojo que antes).

¿Usted realmente necesita este patrón, aunque? ¿Seguro que no puede salirse con:

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

    static Singleton() {} 
    private Singleton() {} 
} 
+1

@JonSkeet, solo para encontrarla; R # se queja de un ctor estático vacío, por lo que causa algún problema si muevo la inicialización de la variable de instancia en el ctor estático. –

+10

@Anindya: No, está bien. Es posible que desee enviar por correo JetBrains para quejarse :) –

+2

@JonSkeet, acabo de plantear una preocupación a JetBrains sobre esto (# RSRP-274373). Veamos qué pueden inventar. :) –

41

cuanto a la pregunta (1): La respuesta de Jon es correcta, ya que implícitamente marca la clase 'anidada' privado al no hacerlo público o interno: -) Es lo mismo que hacerlo de forma explícita mediante la adición de 'privado':

private class Nested 

cuanto a la pregunta (2): básicamente lo the post about beforeinitfield y type initialization te dice es que si usted no tiene ningún constructor estático, el tiempo de ejecución puede inicializar en cualquier momento (pero antes de usarlo). Si tiene un constructor estático, su código en el constructor estático podría inicializar los campos, lo que significa que el tiempo de ejecución solo permite inicializar el campo cuando solicita el tipo.

Por lo tanto, si no desea que el tiempo de ejecución inicialice los campos 'proactivamente' antes de usarlos, agregue un constructor estático.

De cualquier forma, si está implementando singletons, o bien desea que se inicialice lo más lento posible y no cuando el tiempo de ejecución cree que debería inicializar su variable, o probablemente no le importe. De su pregunta, supongo que los quiere lo más tarde posible.

Eso lleva a la publicación de Jon a singleton, que es IMO el tema subyacente de esta pregunta. Ah y las dudas :-)

Me gustaría señalar que su singleton # 3, que marcó "incorrecto", es en realidad correcto (porque el bloqueo es automáticamente implies a memory barrier on exit). También debería ser más rápido que el singleton # 2 cuando usa la instancia más de una vez (que es más o menos el punto de un singleton :-)).Entonces, si realmente necesitas una implementación de singleton perezosa, probablemente vaya por esa, por las simples razones de que (1) está muy claro para todos los que leen tu código lo que está sucediendo y (2) sabes lo que sucederá con excepciones

En caso de que se lo pregunte: nunca usaré el singleton n. ° 6 porque puede provocar bloqueos y comportamientos inesperados con excepciones. Para obtener detalles, consulte: lazy's locking mode, específicamente ExecutionAndPublication.

+51

'Respecto a la pregunta (1): La respuesta de Jon es correcta ...' Jon Skeet ** siempre ** correcto .... – Noctis

+47

Puntos extra por intentar una respuesta sobre una pregunta de Jon Skeet en la que Jon Skeet ya ha respondido . – valdetero

+4

@valdetero Hahaha. Esto ... jajaja +1 – akinuri