2009-06-16 8 views
6

Me preguntaba acerca de algunos CodeWarning (ConstructorsShouldNotCallBaseClassVirtualMethods), y si hay una mejor manera de hacerlo. Tengo una clase de recopilador de registros simple, y estoy usando NHibernate para recuperar algunos de los objetos.Nhibernate - Inicializar listas - ¿Mejores prácticas?

Algunas veces creo objetos por mi cuenta (por supuesto) y los agrego a NHibernate para su persistencia. Cuál es la mejor manera de asegurarse de que Listas nunca sean NULAS.

Actualmente estoy haciendo esto, pero no parece "perfecto". Alguna idea sobre este tema?

public class LogRun 
{ 
    public virtual int Id { get; private set; } 
    public virtual DateTime StartTime { get; set; } 
    public virtual DateTime EndTime { get; set; } 
    public virtual IList<Log> LogMessages { get; set; } 
    public virtual int LogMessageCount { get { return LogMessages.Count; } } 

    public LogRun() 
    { 
     LogMessages = new List<Log>(); 
    } 


} 

Respuesta

8

¿Son los mensajes de registro algo persistente? Si es así, es una buena práctica nunca exponer a un organismo público. NHibernate consigue raro si retreive de la base de datos y luego vuelva a colocar que IList con una nueva:

var myLog = session.Get<LogRun>(1); 
Assert.True(myLog.LogMessages.Count > 0); 
myLog.LogMessages = new List<Log>(); 

Si se observa, NHibernate está volviendo un objeto proxy y su sustitución por una lista genérica hará que se vaya poco firme cuando Intenta y guarda de nuevo.

Como regla general, yo prefiero tener un campo privado que inicializar y luego exponer solamente un captador al cliente:

public class LogRun 
{ 
    private IList<Log> logMessages = new List<Log>(); 

    public virtual int Id { get; private set; } 
    public virtual DateTime StartTime { get; set; } 
    public virtual DateTime EndTime { get; set; } 
    public virtual IList<Log> LogMessages { get { return logMessages; } } 
    public virtual int LogMessageCount { get { return LogMessages.Count; } } 

    public void AddLogMessage(Log log) 
    { 
     logMessages.Add(log); 
    } 
} 

En realidad, voy un paso más allá, el cliente obtiene un IEnumerable <> y agrego una función auxiliar para el complemento.

Mi implmentation se vería

public class LogRun 
{ 
    private IList<Log> logMessages = new List<Log>(); 

    public virtual int Id { get; private set; } 
    public virtual DateTime StartTime { get; set; } 
    public virtual DateTime EndTime { get; set; } 
    public virtual IEnumerable<Log> LogMessages { get { return logMessages; } } 
    public virtual int LogMessageCount { get { return LogMessages.Count(); } } 

    public void AddLogMessage(Log log) 
    { 
     logMessages.Add(log); 
    } 
} 
+2

sigo el mismo patrón, excepto que hago todo mi inicialización en el constructor. Además, generalmente es necesario establecer la referencia al padre en el método add, es decir logMessages.Add (log); log.LogRun = this; –

+2

Voy un paso más allá y hago que mi getter devuelva una versión de solo lectura ... return logMessages.ToList () .AsReadOnly(); – Webjedi

+1

Jamie Ide: Cierto, si es uno con el padre, entonces ese ayudante es un gran lugar para establecerlo. Si es muchos para muchos, entonces no hay un padre. No estoy seguro sobre el contexto aquí, pero sospecho que tienes razón. Webjedi, me gusta su enfoque también. Es por eso que terminé en Enumerable. En mi caso, satisfizo todo lo que quería hacer con la colección. – Ben

1

que hacen lo mismo, pero también me pregunto qué tan grande es el impacto del perfomance, ya que NHibernate también creará una nueva lista de <> para cada llamada al constructor por defecto ..

Creo que estamos en suerte, sin embargo, y que funcionará. Considere NHibernate creación de una lista-perezoso cargado de de LogRun (por eso marcamos todo como virtuales de todos modos):

  1. NHibernate a reflexionar sobre LogRun y ​​crear una clase derivada
  2. NHibernate hará un proxy-lista de la clase derivada de LogRun
  3. -
  4. al cargar ese proxy, se creará una instancia de alguna de esas clases derivadas, sin embargo, la base constructor es llamado primero - la creación de la nueva lista <> - a continuación, el constructor se llama derivada , creando una lista proxy en su lugar.

Efectivamente, hemos creado una lista que nunca usaremos.

considerar las alternativas sin embargo:

  • Hacer el constructor protegido, por lo que nadie va a llamar, y hacer una alternativa. Por ejemplo, un LogRun.GetNew estático(); método.
  • Permita el acceso de configuración público al IList <> y créelo usted mismo cada vez que cree un nuevo objeto.

Honestamente, creo que ambos son muy desordenado, y ya que soy (bastante) asegurarse de que la sobrecarga del perfomance en la creación de una nueva lista vacía en cada constructor de la llamada es limitado, eso es lo que estoy personalmente se pegue demasiado hasta ahora .. Bueno, al menos hasta que mi perfilador me dice lo contrario: P