2010-05-12 17 views
10

sto tornando la variabile che sto creando in un utilizzando istruzione all'interno l'istruzione using (suona strano):restituire la variabile utilizzata per l'utilizzo all'interno del usando C#

public DataTable foo() 
{ 
    using (DataTable properties = new DataTable()) 
    { 
     // do something 
     return properties; 
    } 
} 

sarà questo Smaltire le proprietà delle variabili ??

Dopo aver fatto questo ancora sto ottenendo questo avvertimento:

Attenzione 34 CA2000: Microsoft.Reliability: Nel metodo 'test.test', chiamare System.IDisposable.Dispose sull'oggetto 'proprietà' prima che tutti i riferimenti a è fuori portata.

Qualsiasi idea?

Grazie

+3

Indipendentemente da ciò, questo è solo una cattiva progettazione e deve essere rielaborato. –

risposta

10

Se si desidera tornare, non si può avvolgere in un comunicato using, perché una volta che si lascia le parentesi graffe, che va fuori del campo di applicazione e viene smaltito.

Si dovrà creare un'istanza in questo modo:

public DataTable Foo() 
{ 
    DataTable properties = new DataTable(); 
    return properties; 
} 

e chiamare Dispose() in seguito.

+4

Sembra che 'foo()' == 'GetUsefulDataTable()' e il blocco 'using' dovrebbe essere quello che chiama questa funzione. –

9

Sì, disporrà - e poi restituirlo. Questa è quasi sempre una brutta cosa da fare.

Infatti per DataTable, Dispose quasi mai fa nulla (ad eccezione se è remotato da qualche parte, IIRC) ma è ancora una cattiva idea. Normalmente si dovrebbe considerare inutilizzabili gli oggetti dismessi.

+0

Quindi, quale sarebbe il modello corretto per la restituzione di un oggetto IDisposable da un metodo senza attivare l'avviso CA2000? –

+0

@Jhonny: non lo so, ad essere onesto, non ho usato l'analisi del codice come questo. Mi aspetterei che ci fosse un modo per sopprimere l'avvertimento. –

+0

@ JhonnyD.Cano-Leftware- Se hai intenzione di creare un'istanza e restituire le cose IDisposable, devi metterle esplicitamente nel tuo codice. L'analisi del codice "dovrebbe" rilevare che lo smaltisci altrove manualmente. – IanNorton

3

Il punto di un blocco using è creare un ambito artificiale per un valore/oggetto. Al termine del blocco using, l'oggetto viene ripulito perché non è più necessario. Se vuoi davvero restituire l'oggetto che stai creando, allora non è il caso in cui vuoi usarlo.

Questo funzionerà bene.

public DataTable foo() 
{ 
    DataTable properties = new DataTable(); 
    // do something 
    return properties; 
} 
+0

Funzionerebbe bene se avesse ancora un punto e virgola. = P – Jason

+0

Risolto il problema di battitura. – unholysampler

1

il codice utilizzando la parola chiave utilizzando espande a:

{ 
    DataTable properties = new DataTable(); 
    try 
    { 
     //do something 
     return properties; 
    } 
    finally 
    { 
     if(properties != null) 
     { 
      ((IDisposable)properties).Dispose(); 
     } 
    } 
} 

La variabile è in via di dismissione dalla natura di come utilizzare opere. Se si desidera poter restituire le proprietà, non avvolgerle in un blocco di utilizzo.

7

Presumibilmente, questo è lo schema per un metodo factory che crea un oggetto monouso.Ma, ho ancora visto analisi del codice lamentano anche questo:

 Wrapper tempWrapper = null; 
     Wrapper wrapper = null; 

     try 
     { 
      tempWrapper = new Wrapper(callback); 
      Initialize(tempWrapper); 

      wrapper = tempWrapper; 
      tempWrapper = null; 
     } 
     finally 
     { 
      if (tempWrapper != null) 
       tempWrapper.Dispose(); 
     } 

     return wrapper; 

Questo dovrebbe garantire che se l'inizializzazione fallisce, l'oggetto viene correttamente smaltito, ma se tutto riesce, un'istanza undisposed viene restituito dal metodo .

MSDN Articolo: CA2000: Dispose objects before losing scope.

+0

Non è sostanzialmente equivalente a un blocco catch? Perché non dovresti scrivere 'Wrapper x = null; prova {...} catch {if (x! = null) x.Dispose(); } '. L'intento non è solo il 100% più ovvio, ma evita la variabile temporanea non necessaria e la pulizia manuale. – Juliet

+0

Non sono d'accordo. Ma l'ho appena visto di recente da solo, non perché ero preoccupato di smaltire l'oggetto in caso di errore, ma perché stavo cercando di trovare il modello di codice che eliminasse l'avviso CA2000 senza che dovessi sopprimerlo tramite l'attributo. Il processo di analisi del codice controlla in particolare se l'oggetto è disposto in un blocco finale a causa della natura della regola che viene applicata. Percepisco che questa domanda riguarda davvero CA2000, non lo smaltimento degli oggetti. – Toby

+1

@Juliet: l'istruzione 'catch' manca un rethrow e anche con un rethrow la semantica non è la stessa cosa di non avere un catch. Tra l'altro, se il blocco 'try' contiene chiamate a un metodo' blah' che potrebbe causare un'eccezione, catch-and-rethrow farà sì che la traccia dello stack mostri il numero di riga del rethrow piuttosto che la chiamata a ' blah' (la traccia dello stack all'interno di 'blah' sarà corretta, ma il numero di linea per la chiamata non sarà). – supercat

0

Le altre risposte sono corrette: non appena si esce dal blocco using, l'oggetto viene eliminato. Il blocco using è ottimo per assicurarsi che un oggetto venga smaltito in modo tempestivo, quindi se non si vuole fare affidamento sugli utenti della funzione per ricordare di smaltire l'oggetto in un secondo momento, è possibile provare qualcosa del genere:

public void UsingDataContext (Action<DataContext> action) 
{ 
    using (DataContext ctx = new DataContext()) 
    { 
     action(ctx) 
    } 
} 

questo modo si può dire qualcosa di simile:

var user = GetNewUserInfo(); 
UsingDataContext(c => c.UserSet.Add(user));