À quoi sert «utiliser» en C #?

319

L'utilisateur kokos a répondu à la merveilleuse question Caractéristiques cachées de C # en mentionnant le usingmot - clé. Pourriez-vous préciser ceci? Quelles sont les utilisations de using?

ubermonkey
la source
C'est une façon C # de soutenir l'idiome RAII: hackcraft.net/raii
Nemanja Trifunovic
1
Vous pouvez utiliser pour les objets qui ont implémenté l'interface IDispose. L'utilisation appellera la méthode Dispose lorsque cet objet sort de la portée. Il garantit d'appeler Dispose même si une exception se produit. Il fonctionne comme une clause finally et exécute Dispose.
CharithJ

Réponses:

480

La raison de l' usinginstruction est de s'assurer que l'objet est supprimé dès qu'il sort de la portée, et il ne nécessite pas de code explicite pour garantir que cela se produit.

Comme dans Comprendre l'instruction 'using' en C # (codeproject) et Utiliser des objets qui implémentent IDisposable (microsoft) , le compilateur C # convertit

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

à

{ // 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 introduit une nouvelle syntaxe, nommée "à l' aide de déclarations ":

Une déclaration using est une déclaration de variable précédée du mot clé using. Il indique au compilateur que la variable déclarée doit être supprimée à la fin de la portée englobante.

Ainsi, le code équivalent ci-dessus serait:

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

Et lorsque le contrôle quitte la portée contenante (généralement une méthode, mais il peut également s'agir d'un bloc de code), myResil sera supprimé.

paulwhit
la source
129
Notez qu'il ne s'agit pas nécessairement de disposer correctement de l'objet , mais plutôt de savoir s'il est éliminé en temps opportun. Les objets implémentant IDisposable qui s'accrochent aux ressources non gérées comme les flux et les descripteurs de fichiers implémenteront également un finaliseur qui garantira que Dispose est appelé pendant le garbage collection. Le problème est que le GC pourrait ne pas se produire pendant une période relativement longue. usings'assure que cela Disposeest appelé une fois que vous avez fini avec l'objet.
John Saunders
1
Veuillez noter que le code généré est un peu différent lorsqu'il MyRessources'agit d'une structure. Il n'y a évidemment pas de test de nullité, mais pas de boxe non plus IDisposable. Un appel virtuel contraint est émis.
Romain Verdier
4
Pourquoi personne ne mentionne que l'utilisation est également utilisée pour importer des espaces de noms?
Kyle Delaney
3
Notez que si vous écrivez directement la deuxième version du code, le résultat n'est pas le même. Si vous utilisez le using, la variable construite à l'intérieur est en lecture seule. Il n'y a aucun moyen d'y parvenir pour les variables locales sans l' usinginstruction.
Massimiliano Kraus
1
@JohnSaunders En outre, le finaliseur n'est pas garanti d'être appelé.
Pablo H
124

Puisque beaucoup de gens le font encore:

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

Je suppose que beaucoup de gens ne savent toujours pas que vous pouvez faire:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}
BlackTigerX
la source
2
Est-il possible d'utiliser plusieurs objets de différents types dans une seule instruction using?
Agnel Kurian
12
@AgnelKurian No: "erreur CS1044: impossible d'utiliser plus d'un type dans une instruction for, using, fixed ou declaration"
David Sykes
10
Comment cela répond-il à la question?
Liam
En fait, je ne savais pas que je pouvais en écrire deux à l'aide de statemens avant un seul bloc de code (les imbriquais à chaque fois).
kub1x
97

Des choses comme ça:

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

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

Cela SqlConnectionsera fermé sans avoir besoin d'appeler explicitement la .Close()fonction, et cela se produira même si une exception est levée , sans avoir besoin d'un try/ catch/ finally.

Joel Coehoorn
la source
1
et si j'utilise un "using" dans une méthode, et que je reviens au milieu d'une utilisation. Y a-t-il un problème?
francisco_ssb
1
Il n'y a pas de problème. Dans l'exemple ici, la connexion sera toujours fermée, même si vous êtes returnau milieu du usingbloc.
Joel Coehoorn
30

using peut être utilisé pour appeler IDisposable. Il peut également être utilisé pour les types d'alias.

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

utilisant, dans le sens de

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

Est en fait un raccourci pour un bloc try / finally. Il est équivalent au code:

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

Vous noterez, bien sûr, que le premier extrait est beaucoup plus concis que le second et également qu'il existe de nombreuses sortes de choses que vous voudrez peut-être faire comme nettoyage même si une exception est levée. Pour cette raison, nous avons trouvé une classe que nous appelons Scope qui vous permet d'exécuter du code arbitraire dans la méthode Dispose. Ainsi, par exemple, si vous aviez une propriété appelée IsWorking que vous vouliez toujours définir sur false après avoir tenté d'effectuer une opération, vous le feriez comme ceci:

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

Vous pouvez en savoir plus sur notre solution et comment nous l'avons dérivée ici .

David Mitchell
la source
12

La documentation Microsoft indique que l' utilisation a une double fonction ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), à la fois comme directive et dans les instructions . En tant qu'instruction , comme cela a été souligné ici dans d'autres réponses, le mot clé est essentiellement du sucre syntaxique pour déterminer une portée pour disposer d'un objet IDisposable . En tant que directive , il est couramment utilisé pour importer des espaces de noms et des types. Également en tant que directive, vous pouvez créer des alias pour les espaces de noms et les types, comme indiqué dans le livre "C # 5.0 en bref: le guide définitif" ( http://www.amazon.com/5-0-Nutshell-The- Definitive-Reference-ebook / dp / B008E6I1K8), par Joseph et Ben Albahari. Un exemple:

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

C'est quelque chose à adopter sagement, car l'abus de cette pratique peut nuire à la clarté de son code. Il y a une belle explication sur les alias C #, mentionnant également les avantages et les inconvénients, dans DotNetPearls ( http://www.dotnetperls.com/using-alias ).

Aureliano Buendia
la source
4
Je ne vais pas mentir: je déteste l'utilisation de usingcomme outil d'alias. Cela m'embrouille en lisant le code - je sais déjà qu'il System.Collectionsexiste et a la IEnumerable<T>classe. Utiliser un alias pour l'appeler quelque chose d'autre me l'obscurcit. Je vois using FooCollection = IEnumerable<Foo>comme un moyen pour que les développeurs ultérieurs lisent le code et pensent: "Qu'est-ce que c'est que l'enfer FooCollectionet pourquoi n'y a-t-il pas une classe pour ça quelque part?" Je ne l'utilise jamais et découragerais son utilisation. Mais c'est peut-être juste moi.
Ari Roth
1
Addendum: je concède qu'il pourrait être utile à l'occasion, comme dans votre exemple où vous l'utilisez pour définir un délégué. Mais je dirais que ceux-ci sont relativement rares.
Ari Roth du
10

Je l'ai beaucoup utilisé dans le passé pour travailler avec des flux d'entrée et de sortie. Vous pouvez les imbriquer correctement et cela supprime beaucoup des problèmes potentiels que vous rencontrez habituellement (en appelant automatiquement Dispose). Par exemple:

        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();
                }
            }
        }
Sam Schutte
la source
8

Le simple fait d'ajouter un petit quelque chose qui m'a surpris n'a pas été soulevé. La caractéristique la plus intéressante de l'utilisation (à mon avis) est que peu importe la façon dont vous quittez le bloc à l'aide, il disposera toujours de l'objet. Cela inclut les retours et les exceptions.

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

Peu importe que l'exception soit levée ou que la liste soit renvoyée. L'objet DbContext sera toujours supprimé.

Pluc
la source
6

Une autre grande utilité de l'utilisation consiste à instancier une boîte de dialogue modale.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using
Lucas
la source
1
Voulez-vous dire frm.ShowDialog?
UuDdLrLrSs
5

En conclusion, lorsque vous utilisez une variable locale d'un type qui implémente IDisposable, toujours , sans exception, utilisez using1 .

Si vous utilisez des IDisposablevariables non locales , implémentez toujours le IDisposablemodèle .

Deux règles simples, sans exception 1 . Dans le cas contraire, la prévention des fuites de ressources est une véritable douleur dans les * ss.


1) : La seule exception est - lorsque vous gérez des exceptions. Il pourrait alors y avoir moins de code à appeler Disposeexplicitement dans le finallybloc.

Konrad Rudolph
la source
5

Vous pouvez utiliser l'espace de noms d'alias à l'aide de l'exemple suivant:

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

C'est ce qu'on appelle une directive utilisant l'alias , comme vous pouvez le voir, elle peut être utilisée pour masquer des références de longue haleine si vous souhaitez rendre évident dans votre code ce à quoi vous faites référence, par exemple

LegacyEntities.Account

au lieu de

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

ou simplement

Account   // It is not obvious this is a legacy entity
VictorySaber
la source
4

Fait intéressant, vous pouvez également utiliser le modèle using / IDisposable pour d'autres choses intéressantes (comme l'autre point de la façon dont Rhino Mocks l'utilise). En gros, vous pouvez profiter du fait que le compilateur toujours .Dispose sur l'objet "utilisé". Si vous avez quelque chose qui doit se produire après une certaine opération ... quelque chose qui a un début et une fin définis ... alors vous pouvez simplement créer une classe IDisposable qui commence l'opération dans le constructeur, puis se termine dans la méthode Dispose.

Cela vous permet d'utiliser la syntaxe d'utilisation vraiment agréable pour indiquer le début et la fin explicites de ladite opération. C'est aussi ainsi que fonctionne le système.Transactions.

Joel Martinez
la source
3

Lorsque vous utilisez ADO.NET, vous pouvez utiliser le travail au clavier pour des choses comme votre objet de connexion ou votre objet lecteur. De cette façon, une fois le bloc de code terminé, il supprimera automatiquement votre connexion.

Joseph Daigle
la source
2
J'ajouterais simplement que le bloc de code n'a même pas à se terminer. Un bloc using supprime la ressource même en cas d'exception non gérée.
harpo
Juste pour clarifier davantage, c'est un moyen de s'assurer que le garbage collector s'occupe de vos allocations quand vous le souhaitez, au lieu de le faire quand il le veut.
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 
            }
    }
Shiraj Momin
la source
2

using est utilisé lorsque vous avez une ressource que vous souhaitez supprimer après son utilisation.

Par exemple, si vous allouez une ressource de fichier et que vous n'avez besoin de l'utiliser que dans une section de code pour un peu de lecture ou d'écriture, l'utilisation est utile pour éliminer la ressource de fichier dès que vous avez terminé.

La ressource utilisée doit implémenter IDisposable pour fonctionner correctement.

Exemple:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}
Bob Wintemberg
la source
1

Le mot clé using définit la portée de l'objet, puis supprime l'objet lorsque la portée est terminée. Par exemple.

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

Voir ici pour l'article MSDN sur le mot clé C # using.

David Basarab
la source
1

Ce n'est pas très important, mais l'utilisation peut également être utilisée pour changer les ressources à la volée. Oui jetable comme mentionné précédemment, mais peut-être spécifiquement que vous ne voulez pas que les ressources ne correspondent pas aux autres ressources pendant le reste de votre exécution. Vous voulez donc vous en débarrasser pour qu'il n'interfère pas ailleurs.


la source
1

Grâce aux commentaires ci-dessous, je vais nettoyer un peu ce post (je n'aurais pas dû utiliser les mots 'garbage collection' à l'époque, excuses):
lorsque vous utilisez using, il appellera la méthode Dispose () sur l'objet à la fin de la portée de l'utilisation. Vous pouvez donc avoir un peu de bon code de nettoyage dans votre méthode Dispose ().
Une puce ici qui, espérons-le, obtiendra peut-être ce non-marquage: si vous implémentez IDisposable, assurez-vous d'appeler GC.SuppressFinalize () dans votre implémentation Dispose (), sinon la collecte automatique des ordures essaiera de venir et de la finaliser à certains moments. point, ce qui au moins serait un gaspillage de ressources si vous en avez déjà Dispose () d.

Grank
la source
Cela a un effet indirect. Parce que vous avez supprimé l'objet explicitement, il ne nécessite pas de finalisation et peut donc être GC'd plus tôt.
Kent Boogaart,
1

Autre exemple d'utilisation raisonnable dans laquelle l'objet est immédiatement éliminé:

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);
    }
}
Brendan Kendrick
la source
1

Tout ce qui se trouve à l'extérieur des accolades est éliminé, il est donc préférable de disposer vos objets si vous ne les utilisez pas. En effet, si vous avez un objet SqlDataAdapter et que vous ne l'utilisez qu'une seule fois dans le cycle de vie de l'application et que vous remplissez un seul ensemble de données et que vous n'en avez plus besoin, vous pouvez utiliser le code:

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

L'instruction using fournit un mécanisme pratique pour utiliser correctement les objets IDisposable. En règle générale, lorsque vous utilisez un objet IDisposable, vous devez le déclarer et l'instancier dans une instruction using. L'instruction using appelle la méthode Dispose sur l'objet de la bonne manière et (lorsque vous l'utilisez comme indiqué précédemment), elle provoque également la sortie de l'objet lui-même dès que Dispose est appelé. Dans le bloc using, l'objet est en lecture seule et ne peut pas être modifié ou réaffecté.

Cela vient de: ici

Snowell
la source
1

Pour moi, le nom "using" est un peu déroutant, car il peut s'agir d'une directive pour importer un espace de noms ou une instruction (comme celle discutée ici) pour la gestion des erreurs.

Un nom différent pour la gestion des erreurs aurait été bien, et peut-être plus évident.

Seb
la source
1

Il peut également être utilisé pour créer des étendues pour l'exemple:

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

}
Siamand
la source
1

L'instruction using indique à .NET de libérer l'objet spécifié dans le bloc using une fois qu'il n'est plus nécessaire. Vous devez donc utiliser le bloc «using» pour les classes qui nécessitent un nettoyage après elles, comme les types System.IO.

deepak samantaray
la source
1

Il existe deux utilisations du usingmot clé en C # comme suit.

  1. En tant que directive

    En général, nous utilisons le usingmot - clé pour ajouter des espaces de noms dans les fichiers code-behind et de classe. Ensuite, il met à disposition toutes les classes, interfaces et classes abstraites ainsi que leurs méthodes et propriétés dans la page en cours.

    Exemple:

    using System.IO;
  2. Comme une déclaration

    C'est une autre façon d'utiliser le using mot clé en C #. Il joue un rôle essentiel dans l'amélioration des performances de Garbage Collection.

    le using instruction garantit que Dispose () est appelée même si une exception se produit lorsque vous créez des objets et appelez des méthodes, des propriétés, etc. Dispose () est une méthode présente dans l'interface IDisposable qui aide à implémenter le garbage collection personnalisé. En d'autres termes, si je fais une opération de base de données (insérer, mettre à jour, supprimer) mais qu'en quelque sorte une exception se produit, alors l'instruction using ferme automatiquement la connexion. Pas besoin d'appeler explicitement la méthode de connexion Close ().

    Un autre facteur important est qu'il contribue au regroupement de connexions. Le regroupement de connexions dans .NET permet d'éliminer la fermeture d'une connexion à une base de données plusieurs fois. Il envoie l'objet de connexion à un pool pour une utilisation future (prochain appel à la base de données). La prochaine fois qu'une connexion à la base de données est appelée à partir de votre application, le pool de connexions récupère les objets disponibles dans le pool. Cela permet donc d'améliorer les performances de l'application. Ainsi, lorsque nous utilisons l'instruction using, le contrôleur envoie automatiquement l'objet au pool de connexions, il n'est pas nécessaire d'appeler explicitement les méthodes Close () et Dispose ().

    Vous pouvez faire la même chose que ce que fait l'instruction using en utilisant le bloc try-catch et appeler explicitement le Dispose () à l'intérieur du bloc finally. Mais l'instruction using effectue les appels automatiquement pour rendre le code plus propre et plus élégant. Dans le bloc using, l'objet est en lecture seule et ne peut pas être modifié ou réaffecté.

    Exemple:

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

Dans le code précédent, je ne ferme aucune connexion; il se fermera automatiquement. L' usinginstruction appellera conn.Close () automatiquement en raison de l' usinginstruction ( using (SqlConnection conn = new SqlConnection(connString)) et la même chose pour un objet SqlDataReader. Et si une exception se produit, la connexion se ferme automatiquement.

Pour plus d'informations, consultez Utilisation et importance de l'utilisation en C # .

Chamila Maddumage
la source
0

La syntaxe Rhino Mocks Record-playback fait un usage intéressant de using.

Gilligan
la source
c'est fondamentalement la même chose que d'appeler Playback and Verify tout ce qu'il fait dans les méthodes Dispose ()
George Mauer
-1

l'utilisation comme instruction appelle automatiquement la disposition sur l'objet spécifié. L'objet doit implémenter l'interface IDisposable. Il est possible d'utiliser plusieurs objets dans une même instruction tant qu'ils sont du même type.

Le CLR convertit votre code en MSIL. Et l'instruction using est traduite en un essai et finalement un blocage. C'est ainsi que l'instruction using est représentée en IL. Une déclaration d'utilisation est traduite en trois parties: acquisition, utilisation et élimination. La ressource est d'abord acquise, puis l'utilisation est incluse dans une instruction try avec une clause finally. L'objet est ensuite supprimé dans la clause finally.

Vazgen Torosyan
la source
-3

L'utilisation de Clause est utilisée pour définir la portée de la variable particulière. Par exemple:

     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.
            }
Riya Patil
la source
Cela pourrait induire quelqu'un en erreur en utilisant pour éliminer des objets. Vous confondez peut-être cela avec un bloc de code, si vous voulez limiter la portée d'une variable, vous pouvez utiliser le bloc de code imbriqué pour cela: public static void Main (params string [] args) {{// nested code block}}
luiseduardohd