Skip to content

Commit d6a9a78

Browse files
authored
IDisposable F# snippets (#7766)
1 parent 3972776 commit d6a9a78

File tree

8 files changed

+263
-6
lines changed

8 files changed

+263
-6
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module base1
2+
3+
// <Snippet3>
4+
open Microsoft.Win32.SafeHandles
5+
open System
6+
7+
type BaseClass1() =
8+
// Flag: Has Dispose already been called?
9+
let mutable disposed = false
10+
11+
// Instantiate a SafeHandle instance.
12+
let handle = new SafeFileHandle(IntPtr.Zero, true)
13+
14+
interface IDisposable with
15+
// Public implementation of Dispose pattern callable by consumers.
16+
member this.Dispose() =
17+
this.Dispose true
18+
GC.SuppressFinalize this
19+
20+
// Implementation of Dispose pattern.
21+
abstract Dispose: bool -> unit
22+
override _.Dispose(disposing) =
23+
if not disposed then
24+
if disposing then
25+
handle.Dispose()
26+
// Free any other managed objects here.
27+
disposed <- true
28+
29+
// </Snippet3>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module base2
2+
3+
// <Snippet5>
4+
open System
5+
6+
type BaseClass2() =
7+
// Flag: Has Dispose already been called?
8+
let mutable disposed = false
9+
10+
interface IDisposable with
11+
// Public implementation of Dispose pattern callable by consumers.
12+
member this.Dispose() =
13+
this.Dispose true
14+
GC.SuppressFinalize this
15+
16+
// Implementation of Dispose pattern.
17+
abstract Dispose: bool -> unit
18+
override _.Dispose(disposing) =
19+
if not disposed then
20+
if disposing then
21+
// Free any other managed objects here.
22+
()
23+
24+
// Free any unmanaged objects here.
25+
disposed <- true
26+
27+
override this.Finalize() =
28+
this.Dispose false
29+
// </Snippet5>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module calling1
2+
3+
// <Snippet1>
4+
open System.IO
5+
open System.Text.RegularExpressions
6+
7+
type WordCount(filename) =
8+
let txt =
9+
if File.Exists filename |> not then
10+
raise (FileNotFoundException "The file does not exist.")
11+
12+
use sr = new StreamReader(filename)
13+
sr.ReadToEnd()
14+
15+
let pattern = @"\b\w+\b"
16+
17+
let nWords = Regex.Matches(txt, pattern).Count
18+
19+
member _.FullName = filename
20+
21+
member _.Name = Path.GetFileName filename
22+
23+
member _.Count = nWords
24+
// </Snippet1>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module calling2
2+
3+
// <Snippet2>
4+
open System.IO
5+
open System.Text.RegularExpressions
6+
7+
type WordCount2(filename) =
8+
let txt =
9+
if File.Exists filename |> not then
10+
raise (FileNotFoundException "The file does not exist.")
11+
12+
let sr = new StreamReader(filename)
13+
try
14+
sr.ReadToEnd()
15+
finally
16+
sr.Dispose()
17+
18+
let pattern = @"\b\w+\b"
19+
20+
let nWords = Regex.Matches(txt, pattern).Count
21+
22+
member _.FullName = filename
23+
24+
member _.Name = Path.GetFileName filename
25+
26+
member _.Count = nWords
27+
// </Snippet2>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
module derived1
2+
open System
3+
4+
type MyBaseClass() =
5+
// Flag: Has Dispose already been called?
6+
let mutable disposed = false
7+
8+
interface IDisposable with
9+
// Public implementation of Dispose pattern callable by consumers.
10+
member this.Dispose() =
11+
this.Dispose true
12+
GC.SuppressFinalize this
13+
14+
// Implementation of Dispose pattern.
15+
abstract Dispose: bool -> unit
16+
override _.Dispose(disposing) =
17+
if not disposed then
18+
if disposing then
19+
// Free any other managed objects here.
20+
()
21+
// Free any unmanaged objects here.
22+
disposed <- true
23+
24+
// <Snippet4>
25+
open Microsoft.Win32.SafeHandles
26+
open System
27+
28+
type MyDerivedClass() =
29+
inherit MyBaseClass()
30+
31+
// Flag: Has Dispose already been called?
32+
let mutable disposed = false
33+
// Instantiate a SafeHandle instance.
34+
let handle = new SafeFileHandle(IntPtr.Zero, true)
35+
36+
// Implementation of Dispose pattern.
37+
override _.Dispose(disposing) =
38+
if not disposed then
39+
if disposing then
40+
handle.Dispose()
41+
// Free any other managed objects here.
42+
43+
// Free any unmanaged objects here.
44+
disposed <- true
45+
// Call base class implementation.
46+
base.Dispose disposing
47+
// </Snippet4>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Compile Include="calling1.fs" />
9+
<Compile Include="calling2.fs" />
10+
<Compile Include="base1.fs" />
11+
<Compile Include="base2.fs" />
12+
<Compile Include="derived1.fs" />
13+
<Compile Include="idisposabledispose.fs" />
14+
</ItemGroup>
15+
</Project>
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module idisposabledispose
2+
3+
//<snippet1>
4+
// The following example demonstrates how to create
5+
// a resource class that implements the IDisposable interface
6+
// and the IDisposable.Dispose method.
7+
open System
8+
open System.ComponentModel
9+
open System.Runtime.InteropServices
10+
11+
// Use interop to call the method necessary
12+
// to clean up the unmanaged resource.
13+
[<DllImport "Kernel32">]
14+
extern Boolean CloseHandle(nativeint handle)
15+
16+
// A base class that implements IDisposable.
17+
// By implementing IDisposable, you are announcing that
18+
// instances of this type allocate scarce resources.
19+
type MyResource(handle: nativeint) =
20+
// Pointer to an external unmanaged resource.
21+
let mutable handle = handle
22+
23+
// Other managed resource this class uses.
24+
let comp = new Component()
25+
26+
// Track whether Dispose has been called.
27+
let mutable disposed = false
28+
29+
// Implement IDisposable.
30+
// Do not make this method virtual.
31+
// A derived class should not be able to override this method.
32+
interface IDisposable with
33+
member this.Dispose() =
34+
this.Dispose true
35+
// This object will be cleaned up by the Dispose method.
36+
// Therefore, you should call GC.SuppressFinalize to
37+
// take this object off the finalization queue
38+
// and prevent finalization code for this object
39+
// from executing a second time.
40+
GC.SuppressFinalize this
41+
42+
// Dispose(bool disposing) executes in two distinct scenarios.
43+
// If disposing equals true, the method has been called directly
44+
// or indirectly by a user's code. Managed and unmanaged resources
45+
// can be disposed.
46+
// If disposing equals false, the method has been called by the
47+
// runtime from inside the finalizer and you should not reference
48+
// other objects. Only unmanaged resources can be disposed.
49+
abstract Dispose: bool -> unit
50+
override _.Dispose(disposing) =
51+
// Check to see if Dispose has already been called.
52+
if not disposed then
53+
// If disposing equals true, dispose all managed
54+
// and unmanaged resources.
55+
if disposing then
56+
// Dispose managed resources.
57+
comp.Dispose()
58+
59+
// Call the appropriate methods to clean up
60+
// unmanaged resources here.
61+
// If disposing is false,
62+
// only the following code is executed.
63+
CloseHandle handle |> ignore
64+
handle <- IntPtr.Zero
65+
66+
// Note disposing has been done.
67+
disposed <- true
68+
69+
70+
// This finalizer will run only if the Dispose method
71+
// does not get called.
72+
// It gives your base class the opportunity to finalize.
73+
// Do not provide finalizer in types derived from this class.
74+
override this.Finalize() =
75+
// Do not re-create Dispose clean-up code here.
76+
// Calling Dispose(disposing: false) is optimal in terms of
77+
// readability and maintainability.
78+
this.Dispose false
79+
//</snippet1>

xml/System/IDisposable.xml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,33 @@
6464
## Using an object that implements IDisposable
6565
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:
6666
67-
- By using a language construct such as the `using` statement in C# and Visual Basic.
67+
- By using a language construct such as the `using` statement in C# and Visual Basic, and the `use` statement or `using` function in F#.
6868
6969
- By wrapping the call to the <xref:System.IDisposable.Dispose%2A?displayProperty=nameWithType> implementation in a `try`/`finally` block.
7070
7171
> [!NOTE]
7272
> Documentation for types that implement <xref:System.IDisposable> note that fact and include a reminder to call its <xref:System.IDisposable.Dispose%2A> implementation.
7373
7474
<a name="Using"></a>
75-
### The C# and Visual Basic Using statement
76-
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.
75+
### The C#, F#, and Visual Basic Using statement
76+
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.
7777
7878
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/calling1.cs" id="Snippet1":::
79+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/calling1.fs" id="Snippet1":::
7980
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/calling1.vb" id="Snippet1":::
8081
81-
The `using` statement is actually a syntactic convenience. At compile time, the language compiler implements the intermediate language (IL) for a `try`/`finally` block.
82+
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.
8283
8384
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.
8485
8586
### The Try/Finally block
86-
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.
87+
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.
8788
8889
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/calling2.cs" id="Snippet2":::
90+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/calling2.fs" id="Snippet2":::
8991
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/calling2.vb" id="Snippet2":::
9092
91-
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).
93+
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).
9294
9395
## Implementing IDisposable
9496
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).
@@ -109,11 +111,13 @@
109111
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.
110112
111113
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/base1.cs" id="Snippet3":::
114+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/base1.fs" id="Snippet3":::
112115
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base1.vb" id="Snippet3":::
113116
114117
If you do override the <xref:System.Object.Finalize%2A?displayProperty=nameWithType> method, your class should implement the following pattern.
115118
116119
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/base2.cs" id="Snippet5":::
120+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/base2.fs" id="Snippet5":::
117121
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base2.vb" id="Snippet5":::
118122
119123
Subclasses should implement the disposable pattern as follows:
@@ -127,6 +131,7 @@
127131
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.
128132
129133
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/derived1.cs" id="Snippet4":::
134+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/derived1.fs" id="Snippet4":::
130135
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/derived1.vb" id="Snippet4":::
131136
132137
@@ -136,6 +141,7 @@
136141
137142
:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/CPP/idisposabledispose.cpp" id="Snippet1":::
138143
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/idisposabledispose.cs" id="Snippet1":::
144+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs" id="Snippet1":::
139145
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/VB/idisposabledispose.vb" id="Snippet1":::
140146
141147
]]></format>
@@ -217,6 +223,7 @@
217223
218224
:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/CPP/idisposabledispose.cpp" id="Snippet1":::
219225
:::code language="csharp" source="~/snippets/csharp/System/IDisposable/Overview/idisposabledispose.cs" id="Snippet1":::
226+
:::code language="fsharp" source="~/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs" id="Snippet1":::
220227
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.IDisposable.Dispose Example/VB/idisposabledispose.vb" id="Snippet1":::
221228
222229
]]></format>

0 commit comments

Comments
 (0)