359 votes

Instructions d'utilisation imbriquées en C#

Je travaille sur un projet. Je dois comparer le contenu de deux fichiers et voir s'ils correspondent exactement l'un à l'autre.

Avant un grand nombre de contrôles d'erreurs et de validations, mon premier projet est :

  DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\TestArea\\");
  FileInfo[] files = di.GetFiles(filename + ".*");

  FileInfo outputFile = files.Where(f => f.Extension == ".out").Single<FileInfo>();
  FileInfo expectedFile = files.Where(f => f.Extension == ".exp").Single <FileInfo>();

  using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  {
    using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
      {
        if (outFile.ReadLine() != expFile.ReadLine())
        {
          return false;
        }
      }
      return (outFile.EndOfStream && expFile.EndOfStream);
    }
  }

Il semble un peu étrange d'avoir imbriqué des using déclarations.

Y a-t-il une meilleure façon de procéder ?

0 votes

Je pense avoir trouvé une manière syntaxiquement plus propre de déclarer cette instruction using, et cela semble fonctionner pour moi ? Utiliser var comme type dans l'instruction using au lieu de IDisposable semble me permettre d'instancier mes deux objets et d'appeler leurs propriétés et méthodes de la classe avec laquelle ils sont alloués, comme dans using(var uow = UnitOfWorkType1(), uow2 = UnitOfWorkType2()){}.

0 votes

622voto

SLaks Points 391154

La façon préférée de procéder est de ne mettre qu'une entretoise d'ouverture { après le dernier using comme ceci :

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead())) 
{
    ///...
}

1 votes

J'ai appris quelque chose aujourd'hui. Vous pouvez utiliser cette approche avec différents types. +1

0 votes

Oui, cette approche est intéressante lorsque les types sont différents.

12 votes

Plus propre ? et ne vous oblige pas non plus à utiliser les mêmes types Je procède toujours de cette façon même si les types correspondent pour des raisons de lisibilité et de cohérence.

149voto

Gavin H Points 6366

Si les objets sont de type même type vous pouvez faire ce qui suit

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
                    expFile = new StreamReader(expectedFile.OpenRead()))
{
    // ...
}

1 votes

Ils sont tous du même type et s'ils sont tous jetables, peut-être qu'un plâtre pourrait fonctionner ?

8 votes

@jpierson cela fonctionne, oui, mais ensuite lorsque vous appelez la fonction IDisposable à l'intérieur du bloc using, nous ne pouvons appeler aucun des membres de la classe (sans un cast, ce qui va à l'encontre du but recherché).

0 votes

IDisposable est un type, il suffit donc de l'utiliser comme type pour avoir une liste de types mixtes, comme cela a été vu dans quelques autres réponses.

38voto

Jason Points 125291

Lorsque le IDisposable sont du même type, vous pouvez procéder comme suit :

 using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
     expFile = new StreamReader(expectedFile.OpenRead()) {
     // ...
 }

La page MSDN sur using contient de la documentation sur cette fonctionnalité du langage.

Vous pouvez effectuer les opérations suivantes, que le IDisposable sont du même type :

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamWriter anotherFile = new StreamReader(anotherFile.OpenRead()))
{ 
     // ...
}

19voto

Botz3000 Points 23640

Si cela ne vous dérange pas de déclarer les variables de votre bloc using avant le bloc using, vous pouvez les déclarer toutes dans la même instruction using.

    Test t; 
    Blah u;
    using (IDisposable x = (t = new Test()), y = (u = new Blah())) {
        // whatever...
    }

De cette façon, x et y sont juste des variables de type IDisposable que le bloc using peut utiliser et vous utilisez t et u dans votre code. J'ai juste pensé que je devais le mentionner.

5 votes

J'ai l'impression que cela serait déroutant pour un nouveau développeur qui regarderait votre code.

7 votes

Cela peut être une mauvaise pratique ; cela a pour effet secondaire que les variables existeront toujours même après que les ressources non gérées aient été libérées. Selon la référence C# de Microsoft, "Vous pouvez instancier l'objet ressource et ensuite passer la variable à l'instruction using, mais ce n'est pas une bonne pratique. Dans ce cas, l'objet reste dans la portée après que le contrôle quitte le bloc using, même s'il n'aura probablement plus accès à ses ressources non gérées."

0 votes

@RobertAltman Vous avez raison, et dans un code réel, j'utiliserais une autre approche (probablement celle de Gavin H). Il s'agit simplement d'une alternative moins préférable.

8voto

Jason Williams Points 31901

Si vous voulez comparer les fichiers efficacement, n'utilisez pas du tout les StreamReaders, et alors les utilisations ne sont pas nécessaires - vous pouvez utiliser des lectures de flux de bas niveau pour extraire des tampons de données à comparer.

Vous pouvez également comparer des éléments comme la taille du fichier en premier lieu pour détecter rapidement les différents fichiers et vous éviter de devoir lire toutes les données.

0 votes

Oui, vérifier la taille du fichier est une bonne idée, cela vous évite de lire tous les octets. (+1)

1 votes

Cela ne semble pas répondre à la question, qui porte sur l'imbrication. using (indépendamment de ce que le using contiennent des déclarations). Ce devrait être un commentaire, à la place.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X