2009-06-16 9 views
6

Mi chiedevo solo alcuni CodeWarning (ConstructorsShouldNotCallBaseClassVirtualMethods) e se c'è un modo migliore per farlo. Ho una semplice classe di log collector e sto usando NHibernate per recuperare alcuni oggetti.Nhibere - Inizializza elenchi - Best Practice?

Alcune volte creo oggetti da solo (ovviamente) e li aggiungo a NHibernate per la persistenza. Qual è il modo migliore per assicurarsi che gli elenchi non siano mai NULL.

Attualmente sto facendo questo, ma non sembra "perfetto". Qualche idea su questo argomento?

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


} 

risposta

8

LogMessages è una cosa persistente? Se è così, è meglio non esporre mai un setter pubblico. NHibernate ottiene strano se si retreive dal database e quindi sostituire che IList con uno nuovo:

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

Se si nota, NHibernate sta tornando un oggetto proxy e la sua sostituzione con un elenco generico lo farà per andare wonky quando tu provi a salvare di nuovo.

Come regola generale, preferisco avere un campo privato che inizializzare e quindi esporre solo un getter al client:

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

In realtà, fare un passo ulteriore, il cliente ottiene un IEnumerable <> e aggiungo una funzione di supporto per l'add.

mio implmentation sarebbe simile

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

seguo lo stesso schema, tranne che faccio tutto il mio inizializzazione nel costruttore. Inoltre, è tipicamente necessario impostare il riferimento al genitore nel metodo add, cioè logMessages.Add (log); log.LogRun = this; –

+2

Faccio un passo avanti e restituisco al mio getter una versione di sola lettura ... return logMessages.ToList () .AsReadOnly(); – Webjedi

+1

Jamie Ide: Vero, se è uno-molti con un genitore, allora quell'assistente è un ottimo posto per impostarlo. Se è un multiplo per molti, allora non c'è un genitore. Non sono sicuro sul contesto qui, ma altamente sospetto che tu abbia ragione. Webjedi, mi piace anche il tuo approccio. Ecco perché sono finito su Enumerable. Nel mio caso, ha soddisfatto tutto ciò che volevo fare con la collezione. – Ben

1

mi fanno la stessa cosa, ma mi chiedo anche quanto è grande l'impatto perfomance è, dal momento che NHibernate creerà anche un nuovo elenco <> per ogni chiamata costruttore di default ..

penso che siamo nella fortuna però, e che funzionerà. Si consideri NHibernate creazione di un elenco pigro-caricato su di LogRun (che è il motivo per cui vi segnalo tutto come virtuale in ogni caso):

  1. NHibernate rifletteremo su LogRun e creare una classe derivata
  2. NHibernate farà un proxy-list della classe LogRun-derived
  3. -
  4. Quando si carica che procura, sarà un'istanza di alcune di quelle classi derivate, tuttavia, la base-costruttore viene chiamato prima - la creazione della nuova lista <> - allora il costruttore derivato è chiamato , creando invece una lista di proxy.

In effetti, abbiamo creato un elenco che non useremo mai.

considerare le alternative però:

  • Fai il costruttore protetto, in modo che nessuno chiamerà, e fare in alternativa. Ad esempio, un LogRun.GetNew() statico; metodo.
  • Consentire l'accesso pubblico al IList < e crearlo manualmente ogni volta che si crea un nuovo oggetto.

Onestamente, penso che entrambi sono molto disordinato, e visto che sono (abbastanza) in modo che il sovraccarico perfomance sulla creazione di un nuovo elenco vuoto ogni costruttore-chiamata è limitata, che è quello che sto personalmente attaccare troppo finora ... Beh, almeno fino a quando il mio profiler non mi dice diversamente: P