Come inizializzare l'oggetto che può essere usato nella clausola catch?

2

Ho visto questo tipo di pattern in codice prima:

//pseudo C# code

var exInfo = null;  //Line A

try
{
  var p = SomeProperty;         //Line B
  exInfo = new ExceptionMessage("The property was " + p);           //Line C
}
catch(Exception ex)
{
  exInfo.SomeOtherProperty = SomeOtherValue;  //Line D
}

Di solito il codice è strutturato in questo modo perché exInfo deve essere visibile al di fuori della clausola try. Il problema è che se si verifica un'eccezione sulla riga B, exInfo sarà nullo alla riga D. Il problema sorge quando qualcosa accade sulla linea B che deve verificarsi prima che exInfo venga creato. Ma se imposto exInfo su un nuovo oggetto alla riga A, la memoria potrebbe essere trapelata alla riga C (a causa di "nuovo", ovvero l'oggetto lì). C'è un modello migliore per gestire questo tipo di codice? Esiste un nome per questo tipo di modello di inizializzazione?

A proposito, so che potrei verificare exInfo == null prima della riga D, ma mi sembra un po 'goffo e sto cercando un approccio migliore.

    
posta Onorio Catenacci 17.10.2012 - 21:50
fonte

4 risposte

5

Devi inizializzare exInfo prima il blocco try . In .NET non si perde alcuna memoria sulla linea C.

Proverò a fare un esempio concreto del tuo pseudocodice, e vedere se questo aiuta. Si supponga che db.getList () esegua alcuni SQL e restituisca NULL se non viene trovato nulla, un elenco se sono stati trovati elementi e genera un'eccezione in caso di errore.

List<String> stuff = new ArrayList<String>();

try {
   stuff = db.getList("SELECT someColumn FROM someTable");
}
catch (SqlException e) {
   log.error("Couldn't retrieve stuff!", e);
}

return stuff;

In Java e in altri linguaggi raccolti con garbage, nessuna memoria verrebbe divulgata dopo la riga C se avevi inizializzato la variabile in precedenza. L'oggetto iniziale non avrebbe riferimenti associati e sarebbe quindi idoneo per la garbage collection. Questo modello ti consente di mantenere il codice chiamando questo codice in modo sicuro, poiché restituirà sempre un elenco valido < >.

    
risposta data 17.10.2012 - 21:59
fonte
4

È una buona idea che una variabile non contenga mai un valore errato, se possibile. In questo modo non è possibile, ad esempio, che i manutentori inseriscano in seguito una serie di istruzioni tra la riga A e il blocco try , quindi in qualche punto accidentalmente utilizzi exInfo quando è null . La soluzione generale quando sei tentato di inizializzare un valore su null a causa delle ragioni dell'ambito è di interrompere il codice di inizializzazione nella sua funzione, quindi chiameresti:

var exInfo = createExInfo();

E createExInfo conterrà:

try
{
  var p = SomeProperty;
  return new ExceptionMessage("The property was " + p);
}
catch(Exception ex)
{
  var exInfo = new ExceptionMessage();
  exInfo.SomeOtherProperty = SomeOtherValue;
  return exInfo;
}
    
risposta data 18.10.2012 - 05:49
fonte
1

Mi rifatterò in questo modo:

        var p = null;
        var exInfo = null;

        try
        {
            p = SomeProperty;         //Line B
        }
        catch (Exception ex)
        {
            exInfo = new ExceptionMessage("The property was " + p == null ? "foo" : "bar");           //Line C
            exInfo.SomeOtherProperty = SomeOtherValue;  //Line D
        }

        exInfo.BlahBlahBlah = "Blah";
    
risposta data 17.10.2012 - 22:00
fonte
-1

Che ne dici di creare una classe con un gestore di eventi? Quindi inizializzare exInfo prima di inizializzare var p, il che garantirebbe che exInfo non sarebbe nullo?

    
risposta data 17.10.2012 - 21:57
fonte

Leggi altre domande sui tag