업데이트: 2007년 11월
참고
C++를 사용한 Finalize 및 Dispose에 대한 자세한 내용은 Destructors and Finalizers in Visual C++를 참조하십시오.
클래스 인스턴스는 종종 런타임에서 관리되지 않는 창 핸들(HWND), 데이터베이스 연결 등의 리소스에 대한 제어를 캡슐화합니다. 따라서 이러한 리소스를 해제하는 명시적 방법과 암시적 방법을 모두 제공해야 합니다. 개체에 대해 보호된 Finalize(C# 및 C++의 소멸자 구문)를 구현하여 암시적 제어 수단을 제공합니다. 가비지 수집기는 해당 개체에 대해 유효한 참조가 없어진 후 일정 시점에 이 메서드를 호출합니다.
일부 경우에는 개체를 사용하는 프로그래머에게 가비지 수집기가 해당 개체를 해제하기 전에 이러한 외부 리소스를 명시적으로 해제할 수 있는 기능을 제공할 수도 있습니다. 외부 리소스가 드물고 비싼 경우, 프로그래머가 리소스를 더 이상 사용하지 않을 때 명시적으로 해제하면 성능이 향상될 수 있습니다. 명시적 제어 기능을 제공하려면 IDisposable에서 제공하는 Dispose를 구현합니다. 개체 소비자는 개체 사용이 끝나면 이 메서드를 호출해야 합니다. 해당 개체에 대한 다른 참조가 아직 유지되고 있는 경우에도 Dispose를 호출할 수 있습니다.
Dispose를 사용하여 명시적 제어 기능을 제공하는 경우에도 Finalize 메서드를 사용한 암시적 정리 기능을 제공해야 합니다. Finalize에서는 프로그래머가 Dispose 호출에 실패하는 경우 리소스가 누수되지 않도록 하는 백업 기능을 제공합니다.
Finalize 및 Dispose를 구현하여 관리되지 않는 리소스를 정리하는 방법에 대한 자세한 내용은 가비지 수집을 참조하십시오. 다음 코드 예제에서는Dispose를 구현하기 위한 기본 디자인 패턴을 보여 줍니다. 이 예제에서는 System 네임스페이스가 필요합니다.
' Design pattern for a base class.
Public Class Base
Implements IDisposable
' Field to handle multiple calls to Dispose gracefully.
Dim disposed as Boolean = false
' Implement IDisposable.
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overloads Overridable Sub Dispose(disposing As Boolean)
If disposed = False Then
If disposing Then
' Free other state (managed objects).
disposed = True
End If
End If
' Free your own state (unmanaged objects).
' Set large fields to null.
End Sub
Protected Overrides Sub Finalize()
' Simply call Dispose(False).
Dispose (False)
End Sub
End Class
' Design pattern for a derived class.
Public Class Derived
Inherits Base
' Field to handle multiple calls to Dispose gracefully.
Dim disposed as Boolean = false
Protected Overloads Overrides Sub Dispose(disposing As Boolean)
If disposed = False Then
If disposing Then
' Release managed resources.
disposed = True
End If
End If
' Release unmanaged resources.
' Set large fields to null.
' Call Dispose on your base class.
Mybase.Dispose(disposing)
End Sub
' The derived class does not have a Finalize method
' or a Dispose method without parameters because it inherits
' them from the base class.
End Class
// Design pattern for a base class.
public class Base: IDisposable
{
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
}
// Use C# destructor syntax for finalization code.
~Base()
{
// Simply call Dispose(false).
Dispose (false);
}
}
// Design pattern for a derived class.
public class Derived: Base
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
// Call Dispose on your base class.
base.Dispose(disposing);
}
// The derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits
// them from the base class.
}
Finalize 및 Dispose 구현을 위한 디자인 패턴을 보여 주는 보다 자세한 코드 예제를 보려면 Dispose 메서드 구현을 참조하십시오.
Dispose 메서드 이름 사용자 지정
경우에 따라서는 Dispose 대신 도메인 고유 이름을 사용하는 것이 더 좋습니다. 예를 들어, 파일 캡슐화의 경우에는 Close라는 메서드 이름을 사용할 수 있습니다. 이 경우 Dispose를 전용으로 구현하고 Dispose를 호출하는 공용 Close 메서드를 만듭니다. 다음 코드 예제에서는 이러한 패턴을 보여 줍니다. 여기서 Close는 사용자의 도메인에 적절한 메서드 이름으로 바꿀 수 있습니다. 이 예제에서는 System 네임스페이스가 필요합니다.
' Do not make this method overridable.
' A derived class should not be allowed
' to override this method.
Public Sub Close()
' Call the Dispose method with no parameters.
Dispose()
End Sub
// Do not make this method virtual.
// A derived class should not be allowed
// to override this method.
public void Close()
{
// Call the Dispose method with no parameters.
Dispose();
}
Finalize
다음 규칙은 Finalize 메서드의 사용 지침을 요약한 것입니다.
종료가 필요한 개체에 대해서만 Finalize를 구현합니다. Finalize 메서드를 구현하면 성능이 저하될 수 있습니다.
Finalize 메서드가 필요하면 클래스 사용자가 Finalize 메서드를 호출할 필요가 없도록 IDisposable을 구현할 것인지 고려해야 합니다.
Finalize 메서드를 보다 가시적인 메서드로 만들지 않습니다. 이 메서드는 public이 아니라 protected여야 합니다.
개체의 Finalize 메서드는 해당 개체가 소유하는 모든 외부 리소스를 해제해야 합니다. 또한 Finalize 메서드는 해당 개체에서 보유한 리소스만 해제해야 합니다. Finalize 메서드는 다른 개체를 참조하지 않아야 합니다.
해당 개체의 기본 클래스가 아닌 개체에 대해 Finalize 메서드를 직접 호출하지 않습니다. 이것은 C# 프로그래밍 언어에서는 올바른 작업이 아닙니다.
개체의 Finalize 메서드에서 기본 클래스의 Finalize 메서드를 호출합니다.
참고
기본 클래스의 Finalize 메서드는 C# 및 C++ 소멸자 구문을 사용하여 자동으로 호출됩니다.
Dispose
다음 규칙은 Dispose 메서드의 사용 지침을 요약한 것입니다.
명시적으로 해제되어야 하는 리소스를 캡슐화하는 형식에 대해 dispose 디자인 패턴을 구현합니다. 사용자는 공용 Dispose 메서드를 호출하여 외부 리소스를 해제할 수 있습니다.
일반적으로 기본 형식에 리소스를 계속 사용하는 파생 형식이 있으면 기본 형식에서는 리소스를 계속 사용하지 않더라도 해당 기본 형식에 대해 dispose 디자인 패턴을 구현합니다. 기본 형식에 Close 메서드가 있으면 이는 대개 Dispose를 구현해야 함을 나타냅니다. 이런 경우에는 기본 형식에 대해 Finalize 메서드를 구현하지 않습니다. Finalize는 정리가 필요한 리소스를 사용하는 파생 형식에서 구현되어야 합니다.
형식이 소유하는 삭제 가능한 모든 리소스는 해당 Dispose 메서드에서 해제합니다.
인스턴스에 대해 Dispose를 호출한 후에는 GC.SuppressFinalize를 호출하여 Finalize 메서드가 실행되지 않도록 합니다. 드물지만 Dispose에서 다루지 않는 작업을 Finalize에서 수행해야 하는 경우에는 이 규칙이 적용되지 않습니다.
기본 클래스에서 IDisposable을 구현하면 기본 클래스의 Dispose 메서드를 호출합니다.
Dispose가 호출될 것으로 가정하지 않습니다. 형식에서 소유하는 관리되지 않는 리소스는 Dispose가 호출되지 않는 경우 Finalize 메서드에서도 해제되어야 합니다.
리소스가 이미 삭제되었을 때 해당 형식(Dispose 제외)에 대한 인스턴스 메서드에서 ObjectDisposedException을 throw합니다. Dispose 메서드는 예외를 throw하지 않고 여러 번 호출할 수 있으므로 이 규칙이 적용되지 않습니다.
기본 형식의 계층 구조를 통해 Dispose에 대한 호출을 전파합니다. Dispose 메서드는 해당 개체와 해당 개체 소유의 모든 개체에서 사용하는 리소스를 모두 해제해야 합니다. 예를 들어, 사용자가 모르는 사이에 TextReader에 의해 만들어지는 Stream과 Encoding을 계속 사용하는 TextReader 등의 개체를 만들 수 있습니다. 또한 Stream과 Encoding은 모두 외부 리소스를 받아 들일 수 있습니다. TextReader에 대해 Dispose 메서드를 호출하면 해당 개체는 Stream과 Encoding에 대해 Dispose를 호출하여 해당 외부 리소스를 해제하도록 합니다.
Dispose 메서드가 호출된 다음에는 개체를 다시 사용할 수 없도록 하는 것이 좋습니다. 이미 삭제된 개체를 다시 만드는 것은 구현하기 어려운 패턴입니다.
Dispose 메서드는 예외를 throw하지 않고 한 번 이상 호출될 수 있도록 합니다. 이 메서드는 처음 호출된 이후에는 아무 작업도 수행하지 않습니다.
Portions Copyright 2005 Microsoft Corporation. All rights reserved.
Portions Copyright Addison-Wesley Corporation. All rights reserved.
디자인 지침에 대한 자세한 내용은 2005년에 Addison-Wesley에서 책으로 출간한 Krzysztof Cwalina와 Brad Abrams의 "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries"를 참조하십시오.