Quali sono gli usi di "utilizzo" in C #?


319

L'utente kokos ha risposto alla meravigliosa domanda Hidden Features of C # citando la usingparola chiave. Puoi approfondire questo? A cosa servono using?


È un modo in C # di supportare il linguaggio RAII: hackcraft.net/raii
Nemanja Trifunovic,

1
È possibile utilizzare per gli oggetti che hanno implementato l'interfaccia IDispose. L'utilizzo chiamerà il metodo Dispose quando l'oggetto non rientra nell'ambito. Garantisce di chiamare Dispose anche se si verificano eccezioni. Funziona come una clausola finally ed esegue Dispose.
CharithJ

Risposte:


480

Il motivo usingdell'istruzione è assicurarsi che l'oggetto venga eliminato non appena esca dall'ambito di applicazione e non richiede un codice esplicito per garantire che ciò accada.

Come in Comprensione dell'istruzione "using" in C # (codeproject) e Utilizzo di oggetti che implementano IDisposable (microsoft) , il compilatore C # converte

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

per

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

C # 8 introduce una nuova sintassi, denominata " usando dichiarazioni ":

Una dichiarazione using è una dichiarazione variabile preceduta dalla parola chiave using. Indica al compilatore che la variabile dichiarata deve essere eliminata alla fine dell'ambito che la racchiude.

Quindi il codice equivalente di cui sopra sarebbe:

using var myRes = new MyResource();
myRes.DoSomething();

E quando il controllo lascia l'ambito di contenimento (di solito un metodo, ma può anche essere un blocco di codice), myResverrà eliminato.


129
Si noti che non è necessariamente una questione di disporre correttamente l'oggetto , ma piuttosto se è disposto in modo tempestivo. Gli oggetti che implementano IDisposable che si aggrappano a risorse non gestite come flussi e handle di file implementeranno anche un finalizzatore che assicurerà che venga chiamato Dispose durante la garbage collection. Il problema è che GC potrebbe non accadere per un tempo relativamente lungo. usingsi assicura che Disposevenga chiamato una volta terminato l'oggetto.
John Saunders,

1
Si noti che il codice generato è leggermente diverso quando si MyRessourcetratta di una struttura. Ovviamente non esiste un test per la nullità, ma nemmeno la boxe IDisposable. Viene emessa una chiamata virtuale vincolata.
Romain Verdier,

4
Perché nessuno menziona che l'utilizzo è anche usato per importare spazi dei nomi?
Kyle Delaney,

3
Nota che se scrivi direttamente la seconda versione del codice, il risultato non sarà lo stesso. Se si utilizza il using, la variabile costruita al suo interno è di sola lettura. Non è possibile raggiungere questo obiettivo per le variabili locali senza la usingdichiarazione.
Massimiliano Kraus,

1
@JohnSaunders Inoltre, non è garantito che il finalizzatore venga chiamato.
Pablo H,

124

Dal momento che molte persone fanno ancora:

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

Immagino che molte persone non sappiano ancora che puoi fare:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}

2
È possibile utilizzare più oggetti di diversi tipi in una singola istruzione using?
Agnel Kurian,

12
@AgnelKurian No: "errore CS1044: impossibile utilizzare più di un tipo in un'istruzione for, using, fixed o dichiarazione"
David Sykes,

10
Come risponde alla domanda?
Liam,

In realtà non sapevo di poter scrivere due usando statemens prima di un singolo blocco di codice (li anniderei ogni volta).
kub1x,

97

Cose come questa:

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

Questo SqlConnectionverrà chiuso senza la necessità di chiamare esplicitamente la .Close()funzione e ciò accadrà anche se viene generata un'eccezione , senza la necessità di un try/ catch/ finally.


1
cosa succede se sto usando un "utilizzo" all'interno di un metodo e torno nel mezzo di un utilizzo. C'è qualche problema?
francisco_ssb,

1
Non ci sono problemi Nell'esempio qui, la connessione rimarrà comunque chiusa, anche se si è returndal centro del usingblocco.
Joel Coehoorn,

30

using può essere usato per chiamare IDisposable. Può anche essere usato per alias tipi.

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;

21

usando, nel senso di

using (var foo = new Bar())
{
  Baz();
}

In realtà è una scorciatoia per un blocco try / finally. È equivalente al codice:

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

Noterai, ovviamente, che il primo frammento è molto più conciso del secondo e inoltre ci sono molti tipi di cose che potresti voler fare come ripulitura anche se viene generata un'eccezione. Per questo motivo, abbiamo creato una classe che chiamiamo Scope che ti consente di eseguire codice arbitrario nel metodo Dispose. Quindi, ad esempio, se avessi una proprietà chiamata IsWorking che avresti sempre voluto impostare su false dopo aver provato a eseguire un'operazione, lo faresti in questo modo:

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

Puoi leggere di più sulla nostra soluzione e su come l'abbiamo derivata qui .


12

La documentazione di Microsoft afferma che l' utilizzo ha una doppia funzione ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), sia come direttiva che nelle istruzioni . Come affermazione , come è stato sottolineato qui in altre risposte, la parola chiave è fondamentalmente zucchero sintattico per determinare un ambito per disporre di un oggetto IDisposable . Come direttiva , viene abitualmente utilizzato per importare spazi e tipi di nomi. Anche come direttiva, è possibile creare alias per spazi dei nomi e tipi, come sottolineato nel libro "C # 5.0 In poche parole: la guida definitiva" ( http://www.amazon.com/5-0-Nutshell-The- definitive-Reference-ebook / dp / B008E6I1K8), di Joseph e Ben Albahari. Un esempio:

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

Questo è qualcosa da adottare saggiamente, poiché l'abuso di questa pratica può danneggiare la chiarezza del proprio codice. C'è una bella spiegazione sugli alias C #, che menziona anche pro e contro, in DotNetPearls ( http://www.dotnetperls.com/using-alias ).


4
Non mentirò: odio l'uso di usinguno strumento alias. Mi confonde quando leggo il codice - so già che System.Collectionsesiste e ha la IEnumerable<T>classe. Usare un alias per chiamarlo qualcos'altro lo offusca per me. Vedo using FooCollection = IEnumerable<Foo>come un modo per far sì che gli sviluppatori successivi leggano il codice e pensino: "Che diavolo è un FooCollectione perché non c'è una classe per questo da qualche parte?" Non lo uso mai e ne scoraggerei l'uso. Ma quello potrei essere io.
Ari Roth,

1
Addendum: concedo che potrebbe essere utile occasionalmente, come nel tuo esempio in cui lo usi per definire un delegato. Ma direi che sono relativamente rari.
Ari Roth,

10

L'ho usato molto in passato per lavorare con flussi di input e output. Puoi nidificarli bene e toglie molti dei potenziali problemi che di solito incontri (chiamando automaticamente dispose). Per esempio:

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }

8

L'aggiunta di qualcosa che mi ha sorpreso non è emersa. La caratteristica più interessante dell'utilizzo (secondo me) è che non importa come si esce dal blocco using, esso disporrà sempre l'oggetto. Ciò include resi ed eccezioni.

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

Non importa se viene generata l'eccezione o viene restituito l'elenco. L'oggetto DbContext sarà sempre eliminato.


6

Un altro grande uso dell'utilizzo è l'istanza di una finestra di dialogo modale.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

1
Intendevi frm.ShowDialog?
UuDdLrLrSs

5

In conclusione, quando si utilizza una variabile locale di un tipo che implementa IDisposable, utilizzare sempre , senza eccezioni, using1 .

Se si utilizzano IDisposablevariabili non locali , implementare sempre il IDisposablemodello .

Due semplici regole, nessuna eccezione 1 . Prevenire le perdite di risorse altrimenti è un vero dolore negli * ss.


1) : l'unica eccezione è - quando gestisci le eccezioni. Potrebbe quindi essere meno codice da chiamare Disposeesplicitamente nel finallyblocco.


5

È possibile utilizzare lo spazio dei nomi alias come nell'esempio seguente:

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

Questa è chiamata una direttiva alias che usa come puoi vedere, può essere usata per nascondere riferimenti a lungo termine se vuoi rendere ovvio nel tuo codice ciò a cui ti riferisci ad es.

LegacyEntities.Account

invece di

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

o semplicemente

Account   // It is not obvious this is a legacy entity

4

È interessante notare che puoi anche usare il modello using / IDisposable per altre cose interessanti (come l'altro punto del modo in cui Rhino Mocks lo usa). Fondamentalmente, puoi trarre vantaggio dal fatto che il compilatore lo farà sempre .Disponi sull'oggetto "usato". Se hai qualcosa che deve succedere dopo una certa operazione ... qualcosa che ha un inizio e una fine definiti ... allora puoi semplicemente creare una classe IDisposable che avvia l'operazione nel costruttore e poi termina con il metodo Dispose.

Questo ti permette di usare la sintassi usando davvero piacevole per indicare l'inizio e la fine espliciti di detta operazione. Questo è anche il modo in cui funziona la roba System.Transactions.


3

Quando si utilizza ADO.NET è possibile utilizzare il keywork per cose come l'oggetto connessione o l'oggetto lettore. In questo modo al completamento del blocco di codice, la connessione verrà automaticamente eliminata.


2
Vorrei solo aggiungere che il blocco di codice non deve nemmeno essere completato. Un blocco utilizzo eliminerà la risorsa anche in caso di un'eccezione non gestita.
Harpo,

Giusto per chiarire ulteriormente, è un modo di fare che il Garbage Collector si prende cura dei vostri allocazioni quando si vuole, invece di farlo quando si vuole.
moswald,


3
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }

2

utilizza viene utilizzato quando si dispone di una risorsa che si desidera smaltito dopo che è stato utilizzato.

Ad esempio, se si assegna una risorsa File e è necessario utilizzarla solo in una sezione di codice per una piccola lettura o scrittura, l'utilizzo è utile per eliminare la risorsa File non appena si è terminato.

La risorsa utilizzata deve implementare IDisposable per funzionare correttamente.

Esempio:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}

1

La parola chiave using definisce l'ambito per l'oggetto e quindi elimina l'oggetto quando l'ambito è completo. Per esempio.

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

Vedi qui per l'articolo MSDN sul C # usando la parola chiave.


1

Non che sia estremamente importante, ma l'utilizzo può anche essere utilizzato per modificare le risorse al volo. Sì, usa e getta come indicato in precedenza, ma forse in particolare non si desidera che le risorse non corrispondano ad altre risorse durante il resto dell'esecuzione. Quindi vuoi eliminarlo in modo che non interferisca altrove.


1

Grazie ai commenti qui sotto, pulirò un po 'questo post (non avrei dovuto usare le parole' garbage collection 'al momento, scuse):
quando lo usi usando, chiamerà il metodo Dispose () sull'oggetto alla fine dell'ambito di utilizzo. Quindi puoi avere un bel po 'di ottimo codice di pulizia nel tuo metodo Dispose ().
Un punto elenco che si spera possa ottenere questo svantaggio: se si implementa IDisposable, assicurarsi di chiamare GC.SuppressFinalize () nell'implementazione di Dispose (), poiché altrimenti la garbage collection automatica proverà a venire e finalizzarla in alcuni punto, che almeno sarebbe uno spreco di risorse se ne hai già smaltito () d.


Ha un effetto indiretto. Poiché l'oggetto è stato eliminato in modo esplicito, non richiede la finalizzazione e pertanto può essere GC in precedenza.
Kent Boogaart,

1

Un altro esempio di un uso ragionevole in cui l'oggetto viene immediatamente eliminato:

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}

1

Tutto al di fuori delle parentesi graffe è disposto, quindi è bello disporre i tuoi oggetti se non li usi. Questo perché se hai un oggetto SqlDataAdapter e lo stai usando solo una volta nel ciclo di vita dell'applicazione e stai riempiendo solo un set di dati e non ne hai più bisogno, puoi usare il codice:

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically

1

L'istruzione using fornisce un meccanismo pratico per utilizzare correttamente gli oggetti IDisposable. Di norma, quando si utilizza un oggetto IDisposable, è necessario dichiararlo e creare un'istanza in un'istruzione using. L'istruzione using chiama il metodo Dispose sull'oggetto nel modo corretto e (quando lo si utilizza come mostrato in precedenza) fa sì che l'oggetto stesso esca dall'ambito non appena viene chiamato Dispose. All'interno del blocco using, l'oggetto è di sola lettura e non può essere modificato o riassegnato.

Questo viene da: qui


1

Per me il nome "utilizzo" è un po 'confuso, perché può essere una direttiva per importare uno spazio dei nomi o un'istruzione (come quella discussa qui) per la gestione degli errori.

Un nome diverso per la gestione degli errori sarebbe stato carino e forse in qualche modo più ovvio.


1

Può anche essere utilizzato per la creazione di ambiti per esempio:

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}

1

L'istruzione using indica a .NET di rilasciare l'oggetto specificato nel blocco using una volta che non è più necessario. Quindi dovresti usare il blocco 'using' per le classi che richiedono ripulitura dopo di loro, come i Tipi System.IO.


1

Ci sono due usi della usingparola chiave in C # come segue.

  1. Come una direttiva

    Generalmente usiamo la usingparola chiave per aggiungere spazi dei nomi nei file code-behind e class. Quindi rende disponibili tutte le classi, le interfacce e le classi astratte nonché i loro metodi e proprietà nella pagina corrente.

    Esempio:

    using System.IO;
  2. Come una dichiarazione

    Questo è un altro modo di usare la usingparola chiave in C #. Svolge un ruolo vitale nel miglioramento delle prestazioni in Garbage Collection.

    Il using istruzione assicura che Dispose () venga chiamato anche se si verifica un'eccezione quando si creano oggetti e si chiamano metodi, proprietà e così via. Dispose () è un metodo presente nell'interfaccia IDisposable che aiuta a implementare la Garbage Collection personalizzata. In altre parole, se sto eseguendo alcune operazioni del database (Inserisci, Aggiorna, Elimina) ma in qualche modo si verifica un'eccezione, qui l'istruzione using chiude automaticamente la connessione. Non è necessario chiamare esplicitamente il metodo di connessione Close ().

    Un altro fattore importante è che aiuta nel pool di connessioni. Il pool di connessioni in .NET consente di eliminare più volte la chiusura di una connessione al database. Invia l'oggetto di connessione a un pool per uso futuro (successiva chiamata al database). Alla successiva chiamata di una connessione al database dall'applicazione, il pool di connessioni recupera gli oggetti disponibili nel pool. Quindi aiuta a migliorare le prestazioni dell'applicazione. Pertanto, quando utilizziamo l'istruzione using, il controller invia automaticamente l'oggetto al pool di connessioni, non è necessario chiamare esplicitamente i metodi Close () e Dispose ().

    Puoi fare lo stesso di quello che sta facendo l'istruzione using usando il blocco try-catch e chiamando esplicitamente Dispose () all'interno del blocco finally. Ma l'istruzione using effettua automaticamente le chiamate per rendere il codice più pulito ed elegante. All'interno del blocco using, l'oggetto è di sola lettura e non può essere modificato o riassegnato.

    Esempio:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    using (SqlConnection conn = new SqlConnection(connString))
    {
          SqlCommand cmd = conn.CreateCommand();
          cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
          conn.Open();
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
             while (dr.Read())
             Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
          }
    }

Nel codice precedente non sto chiudendo alcuna connessione; si chiuderà automaticamente. La usingdichiarazione chiamerà conn.Close () automaticamente a causa della usingdichiarazione ( using (SqlConnection conn = new SqlConnection(connString)) e lo stesso per un oggetto SqlDataReader. Inoltre, se si verifica un'eccezione, la connessione verrà chiusa automaticamente.

Per ulteriori informazioni, vedere Utilizzo e importanza dell'utilizzo in C # .



-1

usando come un'istruzione chiama automaticamente lo smaltimento sull'oggetto specificato. L'oggetto deve implementare l'interfaccia IDisposable. È possibile utilizzare più oggetti in un'unica istruzione purché siano dello stesso tipo.

Il CLR converte il codice in MSIL. E l'istruzione using viene tradotta in un tentativo e infine blocco. Ecco come l'istruzione using è rappresentata in IL. Un'istruzione using è tradotta in tre parti: acquisizione, utilizzo e smaltimento. La risorsa viene prima acquisita, quindi l'utilizzo è racchiuso in un'istruzione try con una clausola finally. L'oggetto viene quindi disposto nella clausola finally.


-3

L'utilizzo della clausola viene utilizzato per definire l'ambito per la variabile specifica. Per esempio:

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }

Questo potrebbe fuorviare qualcuno, usando is per lo smaltimento di oggetti. Forse stai confondendo questo con il blocco di codice, se vuoi limitare l'ambito di una variabile puoi usare il blocco di codice nidificato per quello: public static void Main (params string [] args) {{// nested code block}}
luiseduardohd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.