Избегать вложенных блоков, когда внешний используется только для создания внутреннего - PullRequest
0 голосов
/ 05 июля 2018

Часто объект IDisposable блока using сам создается из другого объекта IDisposable, например

using (FileStream stream = File.Open(path, FileMode.Open))
using (MyObject obj = new MyObject(stream))
{
  // do something with obj
}

К сожалению, приведенный выше код сохраняет поток файлов открытым, пока не будет удален объект MyObject.

Чтобы избавиться от файлового потока, как только завершится конструктор MyObject, я мог бы вместо этого написать:

MyObject CreateMyObject(string path)
{
  using (FileStream stream = File.Open(path, FileMode.Open))
  {
    return new MyObject(stream);
  }
}

using (MyObject obj = CreateMyObject(path))
{
  // do something with obj
}

Но мне не нравится многословие этого решения. Я попытался заменить CreateMyObject() на лямбду, но мне не удалось найти допустимый синтаксис. Есть ли способ сделать это без вызова пользовательской функции создателя?


Редактировать: Имея в виду некоторые комментарии, я должен отметить, что я стараюсь избегать try ... finally - своего рода главная причина для блока using в первую очередь.

Дополнительные пояснения: объект MyObject создается из информации в потоке - то есть его конструктор считывает содержимое потока в его целостности. Ни один другой метод в MyObject не ссылается на поток. Содержимое потока может поступать откуда угодно - файл, ресурс, интернет-сокет и т. Д.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Вы можете вызвать магию, например, так:

TResult CreateUsingDisposable<TDisposable, TResult>(TDisposable disposable, Func<TDisposable, TResult> getResult)
  where TDisposable : IDisposable
{
  using (disposable)
  {
    return getResult(disposable);
  }
}

using (var obj = CreateUsingDisposable(new FileStream(path, FileMode.Open), stream => new MyObject(stream)))
{
}

Но почему? Существует супер легко читаемый, не бессмысленный способ сделать это:

  MyObject obj;
  using (var stream = new FileStream(path, FileMode.Open))
  {
    obj = new MyObject(stream);
  }
  using (obj)
  {

  }
0 голосов
/ 05 июля 2018

Хотя я не вижу способа избежать функции создателя, вы можете сделать ее достаточно универсальной, чтобы определить ее один раз и использовать для любого класса:

static T WithStream<T>(string path, Func<FileStream, T> getter)
{
  using (FileStream stream = File.Open(path, FileMode.Open))
  {
    return getter(stream);
  }
}

class MyObject : IDisposable
{
    public MyObject (Stream stream){ /* Work with stream */}
    public void Dispose(){}

}
static void Main()
{

    using (MyObject obj = WithStream("path", fs => new MyObject(fs)))
    {
      // do something with obj
    }
}
...