본문 바로가기

Etc/C#

MemoryStream + StreamReader ??

 

class A : IDisposable

{

public void Dispose()

{

Console.WriteLine("A Dispose()");

}

}

 

class B : IDisposable

{

public void Dispose()

{

Console.WriteLine("B Dispose()");

}

}

 

using (A a = new A())

{

using (B b = new B())

{

 

}

}

=> 코드를 Code Analysis 통해서 Analyze 해보면 "No code analysis issues were detected." 라고 나온다.

 

 

using (MemoryStream ms = new MemoryStream())

{

using (StreamReader reader = new StreamReader(ms))

{

 

}

}

=> 코드를 돌려보면 "Do not dispose objects multiple times" 라고 나온다.

 

얼핏 보면 IDisposable 구현한 클래스들에 대해서는 각각의 Dispose() 호출하는 것이 옳다고 보이나(using 사용하면 마지막 } 에서 Dispose() 호출 ) Code Analysis 위와 같은 결과를 알려줬으므로 우리는 StreamReader 내부적으로 어떻게 작동하는지 확인해볼 필요가 있다.

 

StreamReader TextReader 상속 받았고, TextReader Dispose()에서는 Dispose(bool disposing)를 호출 하도록 되어 있다.

public void Dispose()

{

    this.Dispose(true);

    GC.SuppressFinalize(this);

}

 

Dispose(bool disposing) 다시 virtual 메서드로 StreamReader에서 override 되었다.

StreamReader Dispose(bool dispoing) 보면 다음과 같이 구현이 되어 있다.

 

protected override void Dispose(bool disposing)

{

    try

    {

        if ((!this.LeaveOpen && disposing) && (this.stream != null))

        {

            this.stream.Close();

        }

    }

    finally

    {

        if (!this.LeaveOpen && (this.stream != null))

        {

            this.stream = null;

            this.encoding = null;

            this.decoder = null;

            this.byteBuffer = null;

            this.charBuffer = null;

            this.charPos = 0;

            this.charLen = 0;

            base.Dispose(disposing);

        }

    }

}

 

넘겨진 stream close() 호출해주고 있다. 그렇다면 Stream close 보도록 하자.

 

public virtual void Close()

{

    this.Dispose(true);

    GC.SuppressFinalize(this);

}

 

Dispose(true) 호출하게 되어있다. Dispose(bool disposing) virtual 되어있다.

MemoryStream Dispose(bool dispoing) 보도록 하자.

protected override void Dispose(bool disposing)

{

    try

    {

        if (disposing)

        {

            this._isOpen = false;

            this._writable = false;

            this._expandable = false;

            this._lastReadTask = null;

        }

    }

    finally

    {

        base.Dispose(disposing);

    }

}

 

이런저런 내용들을 정리해주고 있다.

 

 

급작스럽겠지만 MemoryStream Dispse() 보면 다음과 같다.

public void Dispose()

{

    this.Close();

}

 

아까 위에서 봤던 this.Close() 호출해주고 뒤로는 똑같은 작업을 다시 하게 된다.

 

 

여기까지 본다면 사실 MemoryStream Close() StreamReader 1 자신의 Dispose()에서 1 2 호출되게 된다. 하지만 Dispose() 자체가 2 호출되지는 않는데 어째서 Analyze 결과에는 아까와 같은 내용을 보여주는지는 모르겠다. ㅠㅠ

 

아무튼 앞에서 보았던 코드를 다음과 같이 수정을 한다면 아무런 문제가 없다고 나오게 된다.

 

MemoryStream ms = new MemoryStream();

using (StreamReader reader = new StreamReader(ms))

{

 

}

결과는 "No code analysis issues were detected." ~_~

 

그렇다면 결국 ms 해제는 StreamReader에게 맡겨도 되는 것인가? 애매하다 -_-..;;