20

C#では、管理されていないリソースを決定論的にクリーンアップする場合は、「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.
        }
    }
}

C ++では、デストラクタを使用して次のように実行できることに慣れています。

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

これを行うためのC#のより良い方法はありますか?それとも、複数のレベルのネストに固執していますか?

4

10 に答える 10

40

複数の usings でネストする必要はありません。

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
}
于 2008-09-16T19:01:51.180 に答える
8

次のように、開き中括弧の前に using ステートメントをまとめることができます。

  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

于 2008-09-16T19:02:29.230 に答える
3

この構文を使用して、物事を少し要約できます。

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

これは、すべてのブロックに { } を使用しないことが理にかなっている稀なケースの 1 つです。

于 2008-09-16T19:02:31.647 に答える
1

ステートメントを使用してネストする代わりに、.Dispose呼び出しを手動で書き出すことができますが、ある時点でほぼ確実に1つを見逃すことになります。

FxCopまたは、すべてのIDisposable実装型インスタンスに.Dispose()呼び出しがあることを確認できる他の何かを実行するか、ネストを処理します。

于 2008-09-16T19:01:41.417 に答える
1

以前にMichael Meadowsのようなソリューションを実装しましたが、メンバー変数で呼び出されたメソッドが何らかの理由で例外をスローしたStreamWrapper場合、彼のコードは考慮されていません。後続のes は呼び出されず、リソースがぶら下がっている可能性があります。それが機能するためのより安全な方法は次のとおりです。Dispose()Dispose()

        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);
        }
    }
于 2008-09-16T20:25:40.760 に答える
0

この例では、次のものがあると仮定します。

c:\ の下の 1.xml という名前のファイル

複数行のプロパティがオンに設定された、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();
于 2011-05-20T19:48:01.063 に答える
0

一般に、別のストリームに基づいてストリームを作成する場合、新しいストリームは渡されたストリームを閉じることに注意してください。したがって、例をさらに減らすには:

using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
    // all three get disposed when you're done
}
于 2008-09-16T23:32:15.023 に答える
0

次のように中括弧を省略できます。

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
}
于 2008-09-16T19:03:50.270 に答える
0

これにより、コード行数が大幅に増えますが、読みやすさが目に見えて向上します。

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 をリファクタリングして、より汎用的で再利用可能にすることができます。

于 2008-09-16T19:08:55.190 に答える
-1

usingステートメントは、次のように変換されるシンタックスシュガーです。

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

オブジェクトに対して明示的にDisposeを呼び出すことはできますが、オブジェクトの1つが例外をスローすると、リソースが適切に解放されないため、安全性は低くなります。

于 2008-09-16T19:01:13.850 に答える