Aclaración Singleton de Jon Skeet

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();
    }
}

Deseo implementar el patrón Singleton de Jon Skeet en mi aplicación actual en C #.

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();

    ¿Se llama algo cierre?

  2. No puedo entender este comentario.

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

    ¿Qué nos sugiere este comentario?

amutha
fuente
12
jaja pensé que había dicho que estaba un poco preocupado jajaja ... resultó ser un John Nolan diferente
John Antony Daniel Nolan
14
Dos cosas son aceptadas universalmente: el sol sale del este y Jon Skeet siempre tiene la razón. Pero todavía no estoy seguro de lo primero: P
akhil_mittal
2
@ thepirat000: si solo participara en SO / Meta, podría estar en desacuerdo, pero tiene suficiente influencia en el mundo real de la programación que podría ser legítimo, estoy seguro de que alguien lo ha creado en un momento u otro .
Code Jockey
8
La taxonomía de esta pregunta se está discutiendo en meta .
BoltClock

Respuestas:

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

  2. Lea mi artículo sobre beforefieldinit . Es posible que desee o no el constructor estático no operativo: depende de las garantías de pereza que necesite. Debe tener en cuenta que .NET 4 cambia un poco la semántica de inicialización de tipo real (aún dentro de las especificaciones, pero más vago que antes).

¿ Realmente necesitas este patrón? ¿Estás seguro de que no puedes salirte con la tuya?

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

    static Singleton() {}
    private Singleton() {}
}
Jon Skeet
fuente
12
@Anindya: No, está bien. Sin embargo, es posible que desee enviar un correo electrónico a JetBrains para quejarse :)
Jon Skeet
2
@ JonSkeet, acabo de plantearle una preocupación a JetBrains sobre esto (# RSRP-274373). Veamos con qué pueden llegar. :)
Anindya Chatterjee
3
@Lunas: No lo haces. Un singleton vive durante la duración del AppDomain.
Jon Skeet
2
@JonSkeet ¿Alguna razón para no usar Lazy<T>para no tener que declarar un constructor estático para el BeforeFieldInitefecto secundario mágico ?
Ed T
3
FieldBeforeInites MahaBharatadeMicrosoft
Amit Kumar Ghosh
49

Con respecto a la pregunta (1): La respuesta de Jon es correcta, ya que él marca implícitamente la clase como 'Anidada' privada al no hacerla pública o interna :-). También podría hacerlo explícitamente agregando 'privado':

    private class Nested

Con respecto a la pregunta (2): básicamente, lo que la publicación sobre beforeinitfield y type initialization le dice es que si no tiene un constructor estático, el tiempo de ejecución puede inicializarlo en cualquier momento (pero antes de usarlo). Si tiene un constructor estático, su código en el constructor estático puede inicializar los campos, lo que significa que el tiempo de ejecución solo puede inicializar el campo cuando solicita el tipo.

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

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

Eso lleva a la publicación de Jon sobre singleton 's, 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 realmente correcto (porque el bloqueo implica automáticamente una barrera de memoria al salir ). 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 necesita una implementación de singleton perezosa, probablemente iría por esa, por las simples razones de que (1) es muy claro para todos los que leen su código lo que está sucediendo y (2) saben lo que sucederá con excepciones

En caso de que se pregunte: nunca usaría singleton # 6 porque puede conducir fácilmente a puntos muertos y comportamientos inesperados con excepciones. Para obtener detalles, consulte: modo de bloqueo de lazy , específicamente ExecutionAndPublication.

atlaste
fuente
62
Regarding question (1): The answer from Jon is correct ...Jon Skeet siempre tiene razón ...
Noctis
72
Puntos extra por intentar una respuesta sobre una pregunta de Jon Skeet en la que Jon Skeet ya ha respondido.
valdetero
8
@valdetero jajaja. Esto ... jajaja +1
akinuri