Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/base1.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module base1

// <Snippet3>
open Microsoft.Win32.SafeHandles
open System

type BaseClass1() =
// Flag: Has Dispose already been called?
let mutable disposed = false

// Instantiate a SafeHandle instance.
let handle = new SafeFileHandle(IntPtr.Zero, true)

interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this

// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
handle.Dispose()
// Free any other managed objects here.
disposed <- true

// </Snippet3>
29 changes: 29 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/base2.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module base2

// <Snippet5>
open System

type BaseClass2() =
// Flag: Has Dispose already been called?
let mutable disposed = false

interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this

// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
// Free any other managed objects here.
()

// Free any unmanaged objects here.
disposed <- true

override this.Finalize() =
this.Dispose false
// </Snippet5>
24 changes: 24 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/calling1.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module calling1

// <Snippet1>
open System.IO
open System.Text.RegularExpressions

type WordCount(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")

use sr = new StreamReader(filename)
sr.ReadToEnd()

let pattern = @"\b\w+\b"

let nWords = Regex.Matches(txt, pattern).Count

member _.FullName = filename

member _.Name = Path.GetFileName filename

member _.Count = nWords
// </Snippet1>
27 changes: 27 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/calling2.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module calling2

// <Snippet2>
open System.IO
open System.Text.RegularExpressions

type WordCount2(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")

let sr = new StreamReader(filename)
try
sr.ReadToEnd()
finally
sr.Dispose()

let pattern = @"\b\w+\b"

let nWords = Regex.Matches(txt, pattern).Count

member _.FullName = filename

member _.Name = Path.GetFileName filename

member _.Count = nWords
// </Snippet2>
47 changes: 47 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/derived1.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module derived1
open System

type MyBaseClass() =
// Flag: Has Dispose already been called?
let mutable disposed = false

interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this

// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
// Free any other managed objects here.
()
// Free any unmanaged objects here.
disposed <- true

// <Snippet4>
open Microsoft.Win32.SafeHandles
open System

type MyDerivedClass() =
inherit MyBaseClass()

// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a SafeHandle instance.
let handle = new SafeFileHandle(IntPtr.Zero, true)

// Implementation of Dispose pattern.
override _.Dispose(disposing) =
if not disposed then
if disposing then
handle.Dispose()
// Free any other managed objects here.

// Free any unmanaged objects here.
disposed <- true
// Call base class implementation.
base.Dispose disposing
// </Snippet4>
15 changes: 15 additions & 0 deletions snippets/fsharp/System/IDisposable/Overview/fs.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="calling1.fs" />
<Compile Include="calling2.fs" />
<Compile Include="base1.fs" />
<Compile Include="base2.fs" />
<Compile Include="derived1.fs" />
<Compile Include="idisposabledispose.fs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
module idisposabledispose

//<snippet1>
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
open System
open System.ComponentModel
open System.Runtime.InteropServices

// Use interop to call the method necessary
// to clean up the unmanaged resource.
[<DllImport "Kernel32">]
extern Boolean CloseHandle(nativeint handle)

// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
type MyResource(handle: nativeint) =
// Pointer to an external unmanaged resource.
let mutable handle = handle

// Other managed resource this class uses.
let comp = new Component()

// Track whether Dispose has been called.
let mutable disposed = false

// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
interface IDisposable with
member this.Dispose() =
this.Dispose true
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SuppressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize this

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
// Check to see if Dispose has already been called.
if not disposed then
// If disposing equals true, dispose all managed
// and unmanaged resources.
if disposing then
// Dispose managed resources.
comp.Dispose()

// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle handle |> ignore
handle <- IntPtr.Zero

// Note disposing has been done.
disposed <- true


// This finalizer will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide finalizer in types derived from this class.
override this.Finalize() =
// Do not re-create Dispose clean-up code here.
// Calling Dispose(disposing: false) is optimal in terms of
// readability and maintainability.
this.Dispose false
//</snippet1>
19 changes: 13 additions & 6 deletions xml/System/IDisposable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,33 @@
## Using an object that implements IDisposable
If your app simply uses an object that implements the <xref:System.IDisposable> interface, you should call the object's <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation when you are finished using it. Depending on your programming language, you can do this in one of two ways:

- By using a language construct such as the `using` statement in C# and Visual Basic.
- By using a language construct such as the `using` statement in C# and Visual Basic, and the `use` statement or `using` function in F#.

- By wrapping the call to the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation in a `try`/`finally` block.

> [!NOTE]
> Documentation for types that implement <xref:System.IDisposable> note that fact and include a reminder to call its <xref:System.IDisposable.Dispose%2A> implementation.

<a name="Using"></a>
### The C# and Visual Basic Using statement
If your language supports a construct such as the [using](/dotnet/csharp/language-reference/keywords/using) statement in C# and the [Using](/dotnet/visual-basic/language-reference/statements/using-statement) statement in Visual Basic, you can use it instead of explicitly calling <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> yourself. The following example uses this approach in defining a `WordCount` class that preserves information about a file and the number of words in it.
### The C#, F#, and Visual Basic Using statement
If your language supports a construct such as the [using](/dotnet/csharp/language-reference/keywords/using) statement in C#, the [Using](/dotnet/visual-basic/language-reference/statements/using-statement) statement in Visual Basic, or the [use](/dotnet/fsharp/language-reference/resource-management-the-use-keyword) staatement in F#, you can use it instead of explicitly calling <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> yourself. The following example uses this approach in defining a `WordCount` class that preserves information about a file and the number of words in it.

:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/calling1.cs" id="Snippet1":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/calling1.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/calling1.vb" id="Snippet1":::

The `using` statement is actually a syntactic convenience. At compile time, the language compiler implements the intermediate language (IL) for a `try`/`finally` block.
The `using` statement (`use` expression in F#) is actually a syntactic convenience. At compile time, the language compiler implements the intermediate language (IL) for a `try`/`finally` block.

For more information about the `using` statement, see the [Using Statement](/dotnet/visual-basic/language-reference/statements/using-statement) or [using Statement](/dotnet/csharp/language-reference/keywords/using-statement) topics.

### The Try/Finally block
If your programming language does not support a construct like the `using` statement in C# or Visual Basic, or if you prefer not to use it, you can call the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation from the `finally` block of a `try`/`finally` statement. The following example replaces the `using` block in the previous example with a `try`/`finally` block.
If your programming language does not support a construct like the `using` statement in C# or Visual Basic, or the `use` statement in F#, or if you prefer not to use it, you can call the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation from the `finally` block of a `try`/`finally` statement. The following example replaces the `using` block in the previous example with a `try`/`finally` block.

:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/calling2.cs" id="Snippet2":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/calling2.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/calling2.vb" id="Snippet2":::

For more information about the `try`/`finally` pattern, see [Try...Catch...Finally Statement](/dotnet/visual-basic/language-reference/statements/try-catch-finally-statement), [try-finally](/dotnet/csharp/language-reference/keywords/try-finally), or [try-finally Statement](/cpp/c-language/try-finally-statement-c).
For more information about the `try`/`finally` pattern, see [Try...Catch...Finally Statement](/dotnet/visual-basic/language-reference/statements/try-catch-finally-statement), [try-finally](/dotnet/csharp/language-reference/keywords/try-finally), [try...finally Expression](/dotnet/fsharp/language-reference/exception-handling/the-try-finally-expression), or [try-finally Statement](/cpp/c-language/try-finally-statement-c).

## Implementing IDisposable
You should implement <xref:System.IDisposable> if your type uses unmanaged resources directly or if you wish to use disposable resources yourself. The consumers of your type can call your <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation to free resources when the instance is no longer needed. To handle cases in which they fail to call <xref:System.IDisposable.Dispose%2A>, you should either use a class derived from <xref:System.Runtime.InteropServices.SafeHandle> to wrap the unmanaged resources, or you should override the <xref:System.Object.Finalize%2A?displayProperty=nameWithType> method for a reference type. In either case, you use the <xref:System.IDisposable.Dispose%2A> method to perform whatever cleanup is necessary after using the unmanaged resources, such as freeing, releasing, or resetting the unmanaged resources. For more information about implementing <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType>, see [the Dispose(bool) method overload](/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload).
Expand All @@ -109,11 +111,13 @@
The following code fragment reflects the dispose pattern for base classes. It assumes that your type does not override the <xref:System.Object.Finalize%2A?displayProperty=nameWithType> method.

:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/base1.cs" id="Snippet3":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/base1.fs" id="Snippet3":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base1.vb" id="Snippet3":::

If you do override the <xref:System.Object.Finalize%2A?displayProperty=nameWithType> method, your class should implement the following pattern.

:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/base2.cs" id="Snippet5":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/base2.fs" id="Snippet5":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base2.vb" id="Snippet5":::

Subclasses should implement the disposable pattern as follows:
Expand All @@ -127,6 +131,7 @@
The following code fragment reflects the dispose pattern for derived classes. It assumes that your type does not override the <xref:System.Object.Finalize%2A?displayProperty=nameWithType> method.

:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/derived1.cs" id="Snippet4":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/derived1.fs" id="Snippet4":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/derived1.vb" id="Snippet4":::


Expand All @@ -136,6 +141,7 @@

:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/CPP/idisposabledispose.cpp" id="Snippet1":::
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/idisposabledispose.cs" id="Snippet1":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/VB/idisposabledispose.vb" id="Snippet1":::

]]></format>
Expand Down Expand Up @@ -217,6 +223,7 @@

:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/CPP/idisposabledispose.cpp" id="Snippet1":::
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/idisposabledispose.cs" id="Snippet1":::
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/VB/idisposabledispose.vb" id="Snippet1":::

]]></format>
Expand Down