L'utente kokos ha risposto alla meravigliosa domanda Hidden Features of C # citando la using
parola chiave. Puoi approfondire questo? A cosa servono using
?
L'utente kokos ha risposto alla meravigliosa domanda Hidden Features of C # citando la using
parola chiave. Puoi approfondire questo? A cosa servono using
?
Risposte:
Il motivo using
dell'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), myRes
verrà eliminato.
using
si assicura che Dispose
venga chiamato una volta terminato l'oggetto.
MyRessource
tratta di una struttura. Ovviamente non esiste un test per la nullità, ma nemmeno la boxe IDisposable
. Viene emessa una chiamata virtuale vincolata.
using
, la variabile costruita al suo interno è di sola lettura. Non è possibile raggiungere questo obiettivo per le variabili locali senza la using
dichiarazione.
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
}
Cose come questa:
using (var conn = new SqlConnection("connection string"))
{
conn.Open();
// Execute SQL statement here on the connection you created
}
Questo SqlConnection
verrà 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
.
return
dal centro del using
blocco.
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 .
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 ).
using
uno strumento alias. Mi confonde quando leggo il codice - so già che System.Collections
esiste 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 FooCollection
e perché non c'è una classe per questo da qualche parte?" Non lo uso mai e ne scoraggerei l'uso. Ma quello potrei essere io.
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();
}
}
}
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.
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
In conclusione, quando si utilizza una variabile locale di un tipo che implementa IDisposable
, utilizzare sempre , senza eccezioni, using
1 .
Se si utilizzano IDisposable
variabili non locali , implementare sempre il IDisposable
modello .
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 Dispose
esplicitamente nel finally
blocco.
È 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
È 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.
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.
"using" può anche essere usato per risolvere conflitti nello spazio dei nomi. Vedi http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/ per un breve tutorial che ho scritto sull'argomento.
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
}
}
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*
}
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.
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.
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.
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);
}
}
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
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
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);
}
}
}
}
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.
Ci sono due usi della using
parola chiave in C # come segue.
Come una direttiva
Generalmente usiamo la using
parola 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;
Come una dichiarazione
Questo è un altro modo di usare la using
parola 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 using
dichiarazione chiamerà conn.Close () automaticamente a causa della using
dichiarazione ( 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 # .
La sintassi di riproduzione record di Rhino Mocks fa un uso interessante di using
.
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.
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.
}