You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added alert regarding the responsibility of the GC as it relates to implementations of IDisposable (dotnet#24259)
* Address concerns in dotnet#23294
* Apply suggestions from code review
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
* Rename, clean up, add .csproj for CI verification. Add using declaration, etc.
* Even more changes, hopefully that's it
* Pre-commit hook, applied automatic markdownlint CLI fixes
* A few more fixes
* Please work
* does this work now?
* Now that everything is re-written, sigh
* Apply suggestions from code review
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/standard/garbage-collection/implementing-dispose.md
+20-21Lines changed: 20 additions & 21 deletions
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: "Implement a Dispose method"
3
3
description: In this article, learn to implement the Dispose method, which releases unmanaged resources used by your code in .NET.
4
-
ms.date: 04/07/2021
4
+
ms.date: 05/18/2021
5
5
dev_langs:
6
6
- "csharp"
7
7
- "vb"
@@ -44,21 +44,20 @@ The following derived classes in the <xref:Microsoft.Win32.SafeHandles> namespac
44
44
The <xref:System.IDisposable> interface requires the implementation of a single parameterless method, <xref:System.IDisposable.Dispose%2A>. Also, any non-sealed class should have an additional `Dispose(bool)` overload method to be implemented:
45
45
46
46
- A `public` non-virtual (`NonInheritable` in Visual Basic) <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation that has no parameters.
47
-
48
47
- A `protected virtual` (`Overridable` in Visual Basic) `Dispose` method whose signature is:
> The `disposing` parameter should be `false` when called from a finalizer, and `true` when called from the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> method. In other words, it is `true` when deterministically called and `false` when non-deterministically called.
55
54
56
55
### The Dispose() method
57
56
58
57
Because the `public`, non-virtual (`NonInheritable` in Visual Basic), parameterless `Dispose` method is called by a consumer of the type, its purpose is to free unmanaged resources, perform general cleanup, and to indicate that the finalizer, if one is present, doesn't have to run. Freeing the actual memory associated with a managed object is always the domain of the [garbage collector](index.md). Because of this, it has a standard implementation:
The `Dispose` method performs all object cleanup, so the garbage collector no longer needs to call the objects' <xref:System.Object.Finalize%2A?displayProperty=nameWithType> override. Therefore, the call to the <xref:System.GC.SuppressFinalize%2A> method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to <xref:System.GC.SuppressFinalize%2A?displayProperty=nameWithType> has no effect. Note that the actual cleanup is performed by the `Dispose(bool)` method overload.
64
63
@@ -81,8 +80,8 @@ If the method call comes from a finalizer, only the code that frees unmanaged re
81
80
82
81
If your class owns a field or property, and its type implements <xref:System.IDisposable>, the containing class itself should also implement <xref:System.IDisposable>. A class that instantiates an <xref:System.IDisposable> implementation and storing it as an instance member, is also responsible for its cleanup. This is to help ensure that the referenced disposable types are given the opportunity to deterministically perform clean up through the <xref:System.IDisposable.Dispose%2A> method. In this example, the class is `sealed` (or `NotInheritable` in Visual Basic).
> The previous example uses a <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> object to illustrate the pattern; any object derived from <xref:System.Runtime.InteropServices.SafeHandle> could be used instead. Note that the example does not properly instantiate its <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> object.
105
104
106
105
Here's the general pattern for implementing the dispose pattern for a base class that overrides <xref:System.Object.Finalize%2A?displayProperty=nameWithType>.
> In C#, you create a [finalizer](../../csharp/programming-guide/classes-and-structs/destructors.md) by overriding <xref:System.Object.Finalize%2A?displayProperty=nameWithType>. In Visual Basic, this is done with `Protected Overrides Sub Finalize()`.
@@ -120,30 +119,30 @@ A class derived from a class that implements the <xref:System.IDisposable> inter
120
119
121
120
Here's the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:
> The previous example uses a <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> object to illustrate the pattern; any object derived from <xref:System.Runtime.InteropServices.SafeHandle> could be used instead. Note that the example does not properly instantiate its <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> object.
128
127
129
128
Here's the general pattern for implementing the dispose pattern for a derived class that overrides <xref:System.Object.Finalize%2A?displayProperty=nameWithType>:
## Implement the dispose pattern with safe handles
135
134
136
135
The following example illustrates the dispose pattern for a base class, `DisposableStreamResource`, that uses a safe handle to encapsulate unmanaged resources. It defines a `DisposableStreamResource` class that uses a <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> to wrap a <xref:System.IO.Stream> object that represents an open file. The class also includes a single property, `Size`, that returns the total number of bytes in the file stream.
## Implement the dispose pattern for a derived class with safe handles
142
141
143
142
The following example illustrates the dispose pattern for a derived class, `DisposableStreamResource2`, that inherits from the `DisposableStreamResource` class presented in the previous example. The class adds an additional method, `WriteFileInfo`, and uses a <xref:Microsoft.Win32.SafeHandles.SafeFileHandle> object to wrap the handle of the writable file.
Copy file name to clipboardExpand all lines: docs/standard/garbage-collection/using-objects.md
+26-15Lines changed: 26 additions & 15 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,11 @@
1
1
---
2
-
title: "Using objects that implement IDisposable"
2
+
title: Using objects that implement IDisposable
3
3
description: Learn how to use objects that implement the IDisposable interface in .NET. Types that use unmanaged resources implement IDisposable to allow resource reclaiming.
The common language runtime's garbage collector reclaims the memory used by managed objects, but types that use unmanaged resources implement the <xref:System.IDisposable> interface to allow the resources needed by these unmanaged resources to be reclaimed. When you finish using an object that implements <xref:System.IDisposable>, you should call the object's <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType>implementation. You can do this in one of two ways:
17
+
The common language runtime's garbage collector (GC) reclaims the memory used by managed objects. Typically, types that use unmanaged resources implement the <xref:System.IDisposable>or <xref:System.IAsyncDisposable>interface to allow the unmanaged resources to be reclaimed. When you finish using an object that implements <xref:System.IDisposable>, you call the object's <xref:System.IDisposable.Dispose%2A> or <xref:System.IAsyncDisposable.DisposeAsync%2A>implementation to explicitly perform cleanup. You can do this in one of two ways:
18
18
19
-
- With the C# `using` statement (`Using` in Visual Basic).
20
-
- By implementing a `try/finally` block, and calling the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> in the `finally`.
19
+
- With the C# `using` statement or declaration (`Using` in Visual Basic).
20
+
- By implementing a `try/finally` block, and calling the <xref:System.IDisposable.Dispose%2A> or <xref:System.IAsyncDisposable.DisposeAsync%2A> method in the `finally`.
21
+
22
+
> [!IMPORTANT]
23
+
> The GC does ***not*** dispose your objects, as it has no knowledge of <xref:System.IDisposable.Dispose?displayProperty=nameWithType> or <xref:System.IAsyncDisposable.DisposeAsync?displayProperty=nameWithType>. The GC only knows whether an object is finalizable (that is, it defines an <xref:System.Object.Finalize?displayProperty=nameWithType> method), and when the object's finalizer needs to be called. For more information, see [How finalization works](/dotnet/api/system.object.finalize#how-finalization-works). For additional details on implementing `Dispose` and `DisposeAsync`, see:
24
+
>
25
+
> -[Implement a Dispose method](implementing-dispose.md)
26
+
> -[Implement a DisposeAsync method](implementing-disposeasync.md)
27
+
28
+
Objects that implement <xref:System.IDisposable?displayProperty=fullName> or <xref:System.IAsyncDisposable?displayProperty=fullName> should always be properly disposed of, regardless of variable scoping, unless otherwise explicitly stated. Types that define a finalizer to release unmanaged resources usually call <xref:System.GC.SuppressFinalize%2A?displayProperty=nameWithType> from either their `Dispose` or `DisposeAsync` implementation. Calling <xref:System.GC.SuppressFinalize%2A> indicates to the GC that the finalizer has already been run and the object shouldn't be promoted for finalization.
21
29
22
30
## The using statement
23
31
24
32
The [`using` statement](../../csharp/language-reference/keywords/using-statement.md) in C# and the [`Using` statement](../../visual-basic/language-reference/statements/using-statement.md) in Visual Basic simplify the code that you must write to cleanup an object. The `using` statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. However, the `using` statement is useful only for objects that are used within the scope of the method in which they are constructed.
25
33
26
34
The following example uses the `using` statement to create and release a <xref:System.IO.StreamReader?displayProperty=nameWithType> object.
With C# 8, a [`using` declaration](../../csharp/whats-new/csharp-8.md#using-declarations) is an alternative syntax available where the braces are removed, and scoping is implicit.
Although the <xref:System.IO.StreamReader> class implements the <xref:System.IDisposable> interface, which indicates that it uses an unmanaged resource, the example doesn't explicitly call the <xref:System.IO.StreamReader.Dispose%2A?displayProperty=nameWithType> method. When the C# or Visual Basic compiler encounters the `using` statement, it emits intermediate language (IL) that is equivalent to the following code that explicitly contains a `try/finally` block.
The C# `using` statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested `using` statements. The following example instantiates two <xref:System.IO.StreamReader> objects to read the contents of two different files.
Instead of wrapping a `try/finally` block in a `using` statement, you may choose to implement the `try/finally` block directly. It may be your personal coding style, or you might want to do this for one of the following reasons:
43
55
44
56
- To include a `catch` block to handle exceptions thrown in the `try` block. Otherwise, any exceptions thrown within the `using` statement are unhandled.
45
-
46
57
- To instantiate an object that implements <xref:System.IDisposable> whose scope is not local to the block within which it is declared.
47
58
48
59
The following example is similar to the previous example, except that it uses a `try/catch/finally` block to instantiate, use, and dispose of a <xref:System.IO.StreamReader> object, and to handle any exceptions thrown by the <xref:System.IO.StreamReader> constructor and its <xref:System.IO.StreamReader.ReadToEnd%2A> method. The code in the `finally` block checks that the object that implements <xref:System.IDisposable> isn't `null` before it calls the <xref:System.IDisposable.Dispose%2A> method. Failure to do this can result in a <xref:System.NullReferenceException> exception at run time.
You can follow this basic pattern if you choose to implement or must implement a `try/finally` block, because your programming language doesn't support a `using` statement but does allow direct calls to the <xref:System.IDisposable.Dispose%2A> method.
0 commit comments