Подтвердить что ты не робот

Существует ли более эффективная детерминированная схема удаления, чем вложенные "использование"?

В С#, если я хочу детерминистически очистить не управляемые ресурсы, я могу использовать ключевое слово "using". Но для нескольких зависимых объектов это заканчивается в дальнейшем и далее:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
{
    using (BufferedStream bs = new BufferedStream(fs))
    {
        using (StreamReader sr = new StreamReader(bs))
        {
            // use sr, and have everything cleaned up when done.
        }
    }
}

В С++ я привык использовать деструкторы для этого:

{    
    FileStream fs("c:\file.txt", FileMode.Open);
    BufferedStream bs(fs);
    StreamReader sr(bs);
    // use sr, and have everything cleaned up when done.
}

Есть ли лучший способ в С# для этого? Или я застрял с несколькими уровнями гнездования?

4b9b3361

Ответ 1

Вам не нужно вставлять несколько приемов:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
    // all three get disposed when you're done
}

Ответ 2

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

  using (StreamWriter w1 = File.CreateText("W1"))
  using (StreamWriter w2 = File.CreateText("W2"))
  {
      // code here
  }

http://blogs.msdn.com/ericgu/archive/2004/08/05/209267.aspx

Ответ 3

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

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
}

Это один из тех редких случаев, когда не использовать {} для всех блоков имеет смысл ИМХО.

Ответ 4

Вместо того, чтобы вставлять операторы, вы можете просто выписать вызовы .Dispose вручную, но в какой-то момент вы наверняка пропустите один из них.

Либо запустите FxCop, либо что-то еще, чтобы убедиться, что все экземпляры типа экземпляра IDisposable имеют вызов .Dispose() или имеют дело с вложением.

Ответ 5

Я уже реализовал решения, такие как Майкл Медоуз, но его код StreamWrapper не учитывает, если методы Dispose(), вызываемые на переменные-члены throw исключение по той или иной причине, последующие Dispose() es не будут вызваны и ресурсы могут болтаться. Более безопасный способ для работы:

        var exceptions = new List<Exception>();

        try
        {
            this.sr.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        try
        {
            this.bs.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        try
        {
            this.fs.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        if (exceptions.Count > 0)
        {
            throw new AggregateException(exceptions);
        }
    }

Ответ 6

вы можете опустить фигурные скобки, например:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
        // use sr, and have everything cleaned up when done.
}

или используйте обычный метод try finally:

FileStream fs = new FileStream("c:\file.txt", FileMode.Open);
BufferedStream bs = new BufferedStream(fs);
StreamReader sr = new StreamReader(bs);
try
{
        // use sr, and have everything cleaned up when done.
}finally{
   sr.Close(); // should be enough since you hand control to the reader
}

Ответ 7

Это делает намного больше net plus в строках кода, но ощутимым коэффициентом удобочитаемости:

using (StreamWrapper wrapper = new StreamWrapper("c:\file.txt", FileMode.Open))
{
    // do stuff using wrapper.Reader
}

Здесь определяется StreamWrapper:

private class StreamWrapper : IDisposable
{
    private readonly FileStream fs;
    private readonly BufferedStream bs;
    private readonly StreamReader sr;

    public StreamWrapper(string fileName, FileMode mode)
    {
        fs = new FileStream(fileName, mode);
        bs = new BufferedStream(fs);
        sr = new StreamReader(bs);
    }

    public StreamReader Reader
    {
        get { return sr; }
    }

    public void Dispose()
    {
        sr.Dispose();
        bs.Dispose();
        fs.Dispose();
    }
}

С некоторыми усилиями StreamWrapper может быть реорганизован как более общий и многоразовый.

Ответ 8

Следует отметить, что в целом при создании потока, основанного на другом потоке, новый поток закрывает тот, который передается. Таким образом, чтобы еще больше уменьшить ваш пример:

using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
    // all three get disposed when you're done
}

Ответ 9

для этого примера предположим, что у вас есть:

файл с именем 1.xml под c:\

текстовое поле с именем textBox1 с установленными значениями многострочных свойств.

const string fname = @"c:\1.xml";

StreamReader sr=new StreamReader(new BufferedStream(new FileStream(fname,FileMode.Open,FileAccess.Read,FileShare.Delete)));
textBox1.Text = sr.ReadToEnd();

Ответ 10

Оператор using - синтаксический сахар, который преобразуется в:

   try
   {
      obj declaration
      ...
   }
   finally
   {
      obj.Dispose();
   }

Вы можете явно вызвать Dispose на своих объектах, но это будет не так безопасно, так как если один из них выдает исключение, ресурсы не будут правильно освобождены.