[C#] 스트림 객체에 대해 Close () 또는 Dispose ()를 호출해야합니까?

같은 클래스 Stream, StreamReader, StreamWriter등을 구현하는 IDisposable인터페이스를 제공합니다. 즉, Dispose()이러한 클래스의 객체에서 메소드를 호출 할 수 있습니다. 또한 public라는 메소드를 정의했습니다 Close(). 이제 객체로 작업을 마치면 무엇을 호출해야하는지에 대해 혼동됩니다. 둘 다 호출하면 어떻게됩니까?

내 현재 코드는 다음과 같습니다

using (Stream responseStream = response.GetResponseStream())
{
   using (StreamReader reader = new StreamReader(responseStream))
   {
      using (StreamWriter writer = new StreamWriter(filename))
      {
         int chunkSize = 1024;
         while (!reader.EndOfStream)
         {
            char[] buffer = new char[chunkSize];
            int count = reader.Read(buffer, 0, chunkSize);
            if (count != 0)
            {
               writer.Write(buffer, 0, count);
            }
         }
         writer.Close();
      }
      reader.Close();
   }
}

보시다시피, 각 객체에서 using()자동으로 Dispose()메소드를 호출하는 구문을 작성했습니다 . 그러나 나는 또한 Close()메소드 를 호출 합니다. 맞아?

스트림 객체를 사용할 때 모범 사례를 제안하십시오. 🙂

MSDN 예제는 using()구문을 사용하지 않고 Close()메소드를 호출 합니다.

좋은가요?



답변

Reflector.NET으로 빠르게 점프하면 Close()방법 StreamWriter이 다음과 같습니다.

public override void Close()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

그리고 StreamReader:

public override void Close()
{
    this.Dispose(true);
}

Dispose(bool disposing)에서 무시 StreamReader된다

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {
            this.stream = null;
            /* deleted for brevity */
            base.Dispose(disposing);
        }
    }
}

StreamWriter방법은 비슷합니다.

그래서, 코드를 읽는 것은 그것이 분명 당신이 호출 할 수있는 Close()& Dispose()좋아하고 어떤 순서로 당신만큼 자주 스트림에. 어떤 식 으로든 동작을 변경하지 않습니다.

그래서 그것을 사용하는 것이 더 읽을 수 있는지 여부에 내려 오는 Dispose(), Close()및 / 또는 using ( ... ) { ... }.

개인적으로 선호하는 것은 using ( ... ) { ... }가위로 달리지 않는 데 도움이되므로 가능하면 항상 사용하는 것이 좋습니다.

그러나 이것은 정확성에 도움이되지만 가독성은 떨어집니다. C #에는 이미 중괄호를 닫는 것이 너무 많으므로 실제로 어느 것이 스트림에서 클로즈를 수행하는지 어떻게 알 수 있습니까?

그래서 나는 이것을하는 것이 가장 좋다고 생각합니다.

using (var stream = ...)
{
    /* code */

    stream.Close();
}

코드 동작에는 영향을 미치지 않지만 가독성에 도움이됩니다.


답변

아니요, 해당 메소드를 수동으로 호출해서는 안됩니다. using블록 이 끝나면 Dispose()관리되지 않는 리소스를 확보하는 데 도움이 되는 메서드가 자동으로 호출됩니다 (적어도 스트림, 리더 / 라이터 등의 표준 .NET BCL 클래스의 경우). 따라서 다음과 같이 코드를 작성할 수도 있습니다.

using (Stream responseStream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(responseStream))
        using (StreamWriter writer = new StreamWriter(filename))
        {
            int chunkSize = 1024;
            while (!reader.EndOfStream)
            {
                 char[] buffer = new char[chunkSize];
                 int count = reader.Read(buffer, 0, chunkSize);
                 if (count != 0)
                 {
                     writer.Write(buffer, 0, count);
                 }
            }
         }

Close()메소드는를 호출합니다 Dispose().


답변

문서에 따르면이 두 가지 방법은 동일합니다.

StreamReader.Close :이 Close 구현은 True 값을 전달하는 Dispose 메서드를 호출합니다.

StreamWriter.Close :이 Close 구현은 True 값을 전달하는 Dispose 메서드를 호출합니다.

Stream.Close :이 메서드는 Dispose를 호출하여 true를 지정하여 모든 리소스를 해제합니다.

따라서 둘 다 동일하게 유효합니다.

/* Option 1, implicitly calling Dispose */
using (StreamWriter writer = new StreamWriter(filename)) {
   // do something
}

/* Option 2, explicitly calling Close */
StreamWriter writer = new StreamWriter(filename)
try {
    // do something
}
finally {
    writer.Close();
}

개인적으로, 나는 “노이즈”가 적기 때문에 첫 번째 옵션을 고수했습니다.


답변

모두 지원하는 많은 클래스에 Close()Dispose()방법을 두 통화는 상당 할 것이다. 그러나 일부 클래스에서는 닫힌 객체를 다시 열 수 있습니다. 이러한 클래스 중 일부는 재 개설을 허용하기 위해 종료 후 일부 리소스를 유지할 수 있습니다. 다른 것들은 어떤 자원도 살아있게 유지할 수 없지만 명시 적으로 재개를 금지 Close()하도록 플래그를 설정할 수 있습니다 Dispose().

에 대한 계약은 IDisposable.Dispose명시 적으로 다시는 사용되지 않는 객체에서 호출하면 최악의 피해를 입지 않도록 요구하므로 모든 객체에서 IDisposable.Dispose호출되는 메소드 또는 호출하지 않는 메소드를 호출하는 것이 좋습니다 .Dispose()IDisposableClose()


답변

이것은 오래된 질문이지만 이제 각 질문을 차단하지 않고도 문을 사용하여 작성할 수 있습니다. 포함 블록이 완료되면 역순으로 폐기됩니다.

using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream);
using var writer = new StreamWriter(filename);

int chunkSize = 1024;
while (!reader.EndOfStream)
{
    char[] buffer = new char[chunkSize];
    int count = reader.Read(buffer, 0, chunkSize);
    if (count != 0)
    {
        writer.Write(buffer, 0, count);
    }
}

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using


답변