Вложено с помощью операторов в C # - PullRequest
282 голосов
/ 25 августа 2009

Я работаю над проектом. Я должен сравнить содержимое двух файлов и посмотреть, точно ли они соответствуют друг другу.

Перед многими проверками и проверками ошибок мой первый черновик:

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

Кажется немного странным иметь вложенные using операторы.

Есть ли лучший способ сделать это?

Ответы [ 16 ]

505 голосов
/ 25 августа 2009

Предпочтительный способ сделать это - поставить открывающую скобку { после последнего оператора using, например:

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead())) 
{
    ///...
}
126 голосов
/ 25 августа 2009

Если объекты относятся к того же типа , вы можете сделать следующее

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
                    expFile = new StreamReader(expectedFile.OpenRead()))
{
    // ...
}
30 голосов
/ 25 августа 2009

Если IDisposable одного типа, вы можете сделать следующее:

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

На странице MSDN using имеется документация по этой языковой функции.

Вы можете сделать следующее, независимо от того, относятся ли IDisposable к одному типу:

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamWriter anotherFile = new StreamReader(anotherFile.OpenRead()))
{ 
     // ...
}
16 голосов
/ 31 августа 2009

если вы не возражаете объявить переменные для вашего блока использования перед блоком использования, вы можете объявить их все в одном выражении использования.

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

Таким образом, x и y являются просто переменными-заполнителями типа ID, доступными для использования блоком using, и вы используете t и u внутри своего кода. Просто подумал, что упомяну.

9 голосов
/ 25 августа 2009

Если вы хотите эффективно сравнивать файлы, вообще не используйте StreamReaders, и тогда в использовании нет необходимости - вы можете использовать низкоуровневое потоковое чтение для извлечения буферов данных для сравнения.

Вы также можете сначала сравнить такие вещи, как размер файла, чтобы быстро находить разные файлы, чтобы избавить себя от необходимости читать все данные тоже.

8 голосов
/ 17 января 2012

Оператор using работает с интерфейсом IDisposable, поэтому другой вариант может заключаться в создании некоторого типа составного класса, который реализует IDisposable и имеет ссылки на все объекты IDisposable, которые вы обычно помещаете в оператор using. Обратной стороной этого является то, что вы должны сначала объявить свои переменные и выходить за пределы области видимости, чтобы они были полезны в блоке using, требуя больше строк кода, чем требовалось бы для некоторых других предложений.

Connection c = new ...; 
Transaction t = new ...;

using (new DisposableCollection(c, t))
{
   ...
}

Конструктор для DisposableCollection в этом случае является массивом params, поэтому вы можете вводить столько, сколько хотите.

7 голосов
/ 25 августа 2009

Вы также можете сказать:

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

Но некоторым людям может показаться, что их трудно читать. Кстати, как оптимизация вашей проблемы, почему вы не проверяете, чтобы размеры файлов были одинаковыми, прежде чем переходить строка за строкой?

6 голосов
/ 25 августа 2009

Вы можете сгруппировать несколько одноразовых объектов в одном операторе использования с запятыми:

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

}
5 голосов
/ 25 августа 2009

И чтобы просто добавить ясности, в этом случае, поскольку каждый последующий оператор является одним оператором (а не блоком), вы можете опустить все скобки:

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;  
5 голосов
/ 25 августа 2009

Вы можете опустить скобки на всех, кроме самых внутренних, используя:

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

Я думаю, что это чище, чем помещать несколько одинакового типа в одно и то же использование, как предлагали другие, но я уверен, что многие люди подумают, что это сбивает с толку

...