중첩된 "사용"보다 더 나은 결정론적 처리 패턴이 있습니까?

StackOverflow https://stackoverflow.com/questions/75722

  •  09-06-2019
  •  | 
  •  

문제

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#에서 이 작업을 수행하는 더 좋은 방법이 있습니까?아니면 여러 수준의 중첩에 갇혀 있습니까?

도움이 되었습니까?

해결책

여러 용도로 중첩할 필요는 없습니다.

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
}

다른 팁

다음과 같이 여는 중괄호 앞에 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

이 구문을 사용하여 내용을 약간 요약할 수 있습니다.

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

이는 모든 블록에 대해 { }를 사용하지 않는 것이 의미가 있는 드문 경우 중 하나입니다.

using 문을 중첩하는 대신 .Dispose 호출을 수동으로 작성할 수 있지만 어느 시점에서는 거의 확실히 하나를 놓칠 수 있습니다.

FxCop을 실행하거나 모든 IDisposable 구현 유형 인스턴스에 .Dispose() 호출이 있는지 확인하거나 중첩을 처리할 수 있는 다른 것을 실행하십시오.

나는 다음과 같은 솔루션을 구현했습니다. 마이클 메도우즈이전이지만 그의 StreamWrapper 코드는 다음과 같은 경우를 고려하지 않습니다. Dispose() 멤버 변수에 대해 호출된 메서드는 어떤 이유로든 예외를 발생시킵니다. 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);
        }
    }

다음과 같이 중괄호를 생략할 수 있습니다.

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
}

이는 코드 라인에서 훨씬 더 큰 순 플러스를 제공하지만 가독성이 눈에 띄게 향상됩니다.

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를 보다 일반적이고 재사용 가능하도록 리팩토링할 수 있습니다.

일반적으로 다른 스트림을 기반으로 스트림을 생성할 때 새 스트림은 전달되는 스트림을 닫습니다.따라서 예를 더 줄이려면 다음을 수행하십시오.

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

이 예에서는 다음이 있다고 가정합니다.

c:\ 아래에 1.xml이라는 파일

여러 줄 속성이 ON으로 설정된 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();

using 문은 다음과 같이 변환되는 구문 설탕입니다.

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

개체에 대해 명시적으로 Dispose를 호출할 수 있지만 개체 중 하나가 예외를 throw하면 리소스가 제대로 해제되지 않으므로 안전하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top