2010-01-22 8 views
10

Hace poco descubrí propiedades de auto y me gustan bastante. En este momento estoy tratando de usarlos en todas partes donde puedo. No solo para poder usarlos en todas partes, sino para ver qué tan bien funcionan en la mayoría de las situaciones.¿Es una buena idea implementar un singleton usando una auto-propiedad?

Ahora estoy haciendo un singleton y pensé: "Oye, intentemos auto-propiedades aquí también".

public class MySingleton 
{ 
    public static MySingleton MySingleton { get; private set; } 

    private MySingleton() {} 

    static MySingleton() { MySingleton = new MySingleton(); } 
} 

Así que mi pregunta es: "¿Es una buena idea implementar un singleton como este?"

No estoy preguntando si un singleton en general es una buena idea.

Respuesta

14

Yo personalmente no haría eso. No me gusta usar propiedades implementadas automáticamente con un setter privado al que nunca llamas donde realmente quieres una propiedad de solo lectura respaldada por una variable de solo lectura. Es sólo una línea más de código para ser más explícito en lo que se refiere a:

public sealed class MySingleton 
{ 
    private static readonly MySingleton mySingleton; 
    public static MySingleton MySingleton { get { return mySingleton; } } 

    private MySingleton() {} 

    static MySingleton() { mySingleton = new MySingleton(); } 
} 

esta manera de que nadie siquiera tentado para cambiar la clase Singleton para reasignar la propiedad ni de la variable, debido a que el compilador detenerlos. Tendrían que agregar un colocador y/o hacer que la variable no sea solo de lectura, lo cual es un cambio mayor, uno que esperamos reconsideren.

En otras palabras:

  • sí, va a trabajar.
  • No, no creo que sea una buena idea.

Como de C# 6, esto es más fácil con sólo lectura propiedades implementadas automáticamente aunque:

public sealed class MySingleton 
{ 
    public static MySingleton MySingleton { get; } = new MySingleton();  
    private MySingleton() {}   
    static MySingleton() {} 
} 
+0

Estoy totalmente en desacuerdo. Las propiedades automáticas se inventaron para hacer que el código sea más sucinto, lo que hace que el código sea más legible. El argumento de que es un poco más difícil para otros arruinar su diseño no es muy convincente en mi humilde opinión. –

+6

@Philippe: las propiedades automáticas se inventaron para hacer que el código sea más sucinto * donde el código de reemplazo es equivalente al original *. No existe tal equivalencia aquí: está reemplazando una propiedad de solo lectura con una de lectura y escritura, a pesar de que tiene un setter privado. Esto puede parecer trivial, pero prefiero que mi código exprese mis intenciones, y mi intención aquí sería que el valor solo se pueda establecer una vez. La propiedad implementada automáticamente expresa una intención diferente. –

+0

Tiene un punto acerca de la "intención" del colocador, pero al final, para el consumidor de la clase, no hay diferencia alguna. Tener una auto-propiedad con un setter privado es prácticamente lo mismo que tener una propiedad de solo lectura con un campo de respaldo privado. Claro, compila a código diferente, pero es esencialmente el mismo desde el punto de vista del consumidor de la clase. Ahora tengo que abofetearme a mí mismo, porque nunca me han gustado las propiedades automáticas y ahora defiendo su uso (pero ese es un tema para otra pregunta, supongo) –

1

No veo ningún motivo por el que esto no sea correcto. Después de todo, las propiedades automáticas son solo azúcar sintáctica para los usuarios de acceso para un campo de respaldo privado (generado por el compilador).

0

Claro, no veo ningún problema con eso.

3

Consulte this sobre cómo implementar Singleton correctamente.

Y sabe que los singleton son malvados, ¿verdad?

+0

+1 mejor forma de implementar singletons: utilice un contenedor DI y establezca el tipo en el alcance singleton. –

+6

"No estoy preguntando si un singleton en general es una buena idea". –

+0

La pregunta también recibió una respuesta correcta, su blog obtuvo accesorios. –

8

Me gustaría acercarse a esto desde una dirección ligeramente diferente de Jon. Independientemente de si el objeto es un singleton, es el mejor modelo lógicamente como una propiedad en primer lugar?

Se supone que las propiedades representan ... propiedades. (¡El Capitán Obvio ataca de nuevo!) Ya sabes. Color. Longitud. Altura. Nombre. Padre. Todo lo que lógicamente considerarías como propiedad de una cosa.

No puedo concebir un propiedad de un objeto que es lógicamente un Singleton. Quizás hayas pensado en un escenario en el que no había pensado; No he tenido ninguna Dieta Dr. Pepper aún esta mañana. Pero sospecho que esto es un abuso de la semántica del modelo.

¿Puede describir qué es el singleton y por qué cree que es propiedad de algo?

Dicho todo esto, yo mismo uso este patrón con frecuencia; usualmente así:

class ImmutableStack<T> 
{ 
    private static readonly ImmutableStack<T> emptystack = whatever; 
    public static ImmutableStack<T> Empty { get { return emptystack; } } 
    ... 

¿Está "vacío" lógicamente una propiedad de una pila inmutable? No. Aquí, el atractivo beneficio de poder decir

var stack = ImmutableStack<int>.Empty; 

supera mi deseo de que las propiedades sean lógicamente propiedades. Diciendo

var stack = ImmutableStack<int>.GetEmpty(); 

just seems weird.

Si es mejor en este caso tener un campo de solo lectura y una propiedad regular, o un ctor estático y un autoprop, parece una pregunta menos interesante que si se trata de una propiedad en primer lugar. En un estado de ánimo "purista", probablemente me pondría del lado de Jon y lo convertiría en un campo de solo lectura. Pero también utilizo frecuentemente el patrón de hacer autoprops con setters privados para objetos lógicamente inmutables, solo por pereza.

¿Cómo es eso de tomar todas las partes de una pregunta?

+0

Hmm, interesante. Nunca consideré las propiedades de esa manera. Para mí, siempre han sido un reemplazo para los métodos de acceso. En cierto modo, vi los métodos de acceso como una forma de mejorar los campos públicos (ocultar parcialmente, poner en la interfaz, agregar alguna información de control). Y luego propiedades para poder obtener una forma más intuitiva que getters y setters. Entonces, para mí, una propiedad nunca debe ser lógicamente una propiedad de las cosas que la clase representa. Para mí, una propiedad es cómo se ve un campo desde el exterior. –

+0

¿Podría explicar el beneficio de la sintaxis similar a la propiedad en su ejemplo 'ImmutableStack .Empty'?Me gustaría entender mejor qué beneficio logras aquí, particularmente porque en LINQ 'Enumerable.Empty ()' es similar al tipo de sintaxis que evitas en ese ejemplo. – LBushkin

+0

@LBushkin - Supongo que "vacío" frente a "vacío()" frente a "GetEmpty()" son todas pequeñas diferencias. ¡Creo que un "beneficio convincente" fue una exageración! :-) –

0

¿Propiedad del auto? No, no lo haría, pero usando un setter en un singleton, sí lo hice. Creo que quieres más control sobre él que una propiedad de auto te dará.

... comentarios constructivos son más que bienvenidos aquí, por favor. Esto se siente como un movimiento valiente (o tonto) en esta compañía estimada ...

Mi escenario, una aplicación WPF que tiene un proyecto actual que se puede cargar y guardar. La configuración actual del proyecto se utilizan en todo el aplicación ...

  • en los enlaces de WPF en la interfaz de usuario que el usuario pueda cambiar la configuración, por lo tanto, la interfaz INotifyPropertyChanged.
  • También uso Fody.PropertyChanged pero eso no hace cambios de propiedad estáticos, por lo tanto NotifyStaticPropertyChanged.
  • INotifyPropertyChanged funciona bien con enlaces WPF en las propiedades de singleton.
  • Una instancia del Settings se [serializa] utilizando JSON.NET, de ahí el atributo [JsonIgnore] en el singleton. Lo valido antes de cargarlo en el singleton o guardarlo en el disco.
  • el registrador es Serilog. Usted registra cosas, ¿verdad?
  • el singleton es public con un getter public porque los enlaces WPF solo funcionan en propiedades públicas. El setter internal no lo afecta. Todas las propiedades de Settings son públicas para WPF vinculante.

Dejé todo el "ruido" en el código porque a algunos les puede resultar útil.

class Settings : INotifyPropertyChanged 
{ 
    private static Settings _currentSettings = new Settings(); 

    /// <summary> The one and only Current Settings that is the current Project. </summary> 
    [JsonIgnore] // so it isn't serialized by JSON.NET 
    public static Settings CurrentSettings // http://csharpindepth.com/Articles/General/Singleton.aspx 
    { 
     get { return _currentSettings; } 

     // setter is to load new settings into the current settings (using JSON.NET). Hey, it works. Probably not thread-safe. 
     internal set 
     { 
      Log.Verbose("CurrentSettings was reset. Project Name: {projectName}", value.ProjectName); 
      _currentSettings = value; 
      _currentSettings.IsChanged = false; 
      NotifyStaticPropertyChanged("CurrentSettings"); 
     } 
    } 

    // http://10rem.net/blog/2011/11/29/wpf-45-binding-and-change-notification-for-static-properties 
    /// <summary> Fires when the Curent CurrentTvCadSettings is loaded with new settings 
    ///   Event queue for all listeners interested in StaticPropertyChanged events. </summary> 
    public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged = delegate { }; 
    private static void NotifyStaticPropertyChanged(string propertyName) 
    { 
     StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName)); 
    } 

    // various instance properties including .... 

    public string ProjectName {get; set;} 

    [JsonIgnore] 
    public bool IsChanged { get; set; } 
} 

uso para establecer el singleton a un proyecto recién cargada, settings es simplemente

Settings settings = new Settings(); 
// load, save, deserialize, set properties, go nuts 
Settings.CurrentSettings = settings; 

El colocador probablemente no es seguro para subprocesos, pero yo sólo puse en un lugar desde el subproceso de interfaz de usuario de modo No tengo miedo. Puede hacer que sea seguro para hilos siguiendo los consejos estimados en http://csharpindepth.com/Articles/General/Singleton.aspx

Me doy cuenta de que OP no preguntó por WPF, pero creo que es relevante mostrar por qué es posible que desee establecer un singleton. Lo hice porque es la solución más simple.

Cuestiones relacionadas