2010-05-02 17 views
8

me gustaría hacer algo como esto:¿Es una mala práctica tener estado en una clase estática?

public class Foo { 
    // Probably really a Guid, but I'm using a string here for simplicity's sake. 
    string Id { get; set; } 

    int Data { get; set; } 

    public Foo (int data) { 
     ... 
    } 

    ... 
} 

public static class FooManager { 
    Dictionary<string, Foo> foos = new Dictionary<string, Foo>(); 

    public static Foo Get (string id) { 
     return foos [id]; 
    } 

    public static Foo Add (int data) { 
     Foo foo = new Foo (data); 
     foos.Add (foo.Id, foo); 

     return foo; 
    } 

    public static bool Remove (string id) { 
     return foos.Remove (id); 
    } 

    ... 

    // Other members, perhaps events for when Foos are added or removed, etc. 
} 

Esto me permitiría gestionar la recolección mundial de Foo s desde cualquier lugar. Sin embargo, me han dicho que las clases estáticas siempre deben ser sin estado, no debe usarlas para almacenar datos globales. La información global en general parece estar mal vista. Si no debería usar una clase estática, ¿cuál es la forma correcta de abordar este problema?

Nota: Encontré un similar question, pero la respuesta dada no se aplica realmente en mi caso.

Respuesta

9

¿Quién se queda que las clases estáticas deberían ser sin estado? Estático significa indicado.

sólo saben cómo funcionan las clases estática en el CLR:

  • No se puede controlar el momento en que se llaman constructores estáticos.
  • Las clases estáticas tienen un estado separado para cada programa de llamada.

También tenga en cuenta los problemas de simultaneidad.

Como nota al margen, me sorprende con qué frecuencia la gente dice "No use X". Sería como si alguien entrara en su cobertizo de herramientas y señalara media docena de herramientas y dijera: "Esas herramientas son una mala práctica". No tiene sentido.

+1

Sí, todos deberíamos usar más variables globales y gotos ... – Lucas

+1

Úselo cuando sea necesario, pero sea inteligente para evitar problemas. Más tarde sé ágil para moverte a algo mejor. –

3

Lo que parece estar buscando aquí es una clase singleton, no una clase estática. Las clases y métodos estáticos deben ser referidos para rutinas sin estado. Una clase única se instancia una vez y solo una vez por cada aplicación ejecutada y tiene la funcionalidad completa de una clase como tal. Cada vez que lo referencia en el futuro, obtendrá la misma instancia exacta con exactamente las mismas propiedades de miembro.

El primer resultado de google para "C# singleton" parece tener una explicación bastante decente para la implementación. http://www.yoda.arachsys.com/csharp/singleton.html

+1

tenga en cuenta que los singletons tampoco son una buena práctica, porque crean dependencias, etc. Al final, IoC (Inversion of Control) y Dependency Injection serían una mejor solución. – Femaref

4

Los datos globales son poderosos y una fuente común de problemas, por eso se utilizan técnicas como la inyección de dependencia. Puedes pensar que es un problema de desacoplamiento normal. Tener datos globales a los que se hace referencia directamente en muchos lugares de su programa constituye un fuerte acoplamiento entre los datos globales y todos esos lugares.

En su ejemplo, sin embargo, ha aislado el acceso a los datos en una clase, que controla los detalles exactos del acceso de los datos globales. Como algunos datos globales son a menudo inevitables, creo que este es un buen enfoque.

Puede comparar, por ejemplo, cómo se utilizan app.config y web.config a través de .NET Framework. Se accede a ellos a través de una clase estática System.Configuration.ConfigurationManager con una propiedad estática AppSettings, que oculta los detalles de cómo llegar a los datos globales.

2

En general no es malo. En algunos casos raros, es necesario hacerlo de esa manera que implementar otra cosa con grandes gastos generales.

Pero se recomienda mirar para la seguridad del hilo.

Debe bloquear cada llamada a su diccionario para que solo un hilo pueda acceder a ella a la vez.


private static readonly object LockStaticFields = new object(); 

public static Foo Add (int data) { 
     lock(LockStaticFields) 
     { 
      Foo foo = new Foo (data); 
      foos.Add (foo.Id, foo); 

      return foo; 
     } 
    } 

+0

Agregaría: "Debería bloquear cada llamada a su diccionario" si está trabajando en un entorno de subprocesos múltiples. De lo contrario, será una sobrecarga inútil – Budda

+0

Hmm, quizás tengas razón. Pero mi experiencia me dice que es mejor hacerlo siempre de esa manera. Estoy trabajando en una empresa que ahora tiene que refaccionar casi todo porque inicialmente no se implementó para entornos de subprocesamiento múltiple. Creo que esto cuesta mucho más que implementarlo en hilo la primera vez, aunque es posible que no necesite esta seguridad. – DHN

0

Utilice una propiedad estática de solo lectura en su clase, esta propiedad será la misma en todas las instancias de la clase. Increméntelo y disminuya según sea necesario desde el constructor, etc.

0

Utilizo listas en clases estáticas todo el tiempo para cosas que nunca (o muy raramente) cambiarán - útiles para cargar listas de selección y demás sin pulsar el db todo el tiempo. Como no permito los cambios, no tengo que preocuparme por el bloqueo/control de acceso.

0

Otra cosa a tener en cuenta es la aplicación en sí y el presupuesto para ello. ¿Existe realmente la necesidad de algo más complejo que una clase estática?

Cuestiones relacionadas