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에게 맡겨도 되는 것인가? 애매하다 -_-..;;