diff --git a/snippets/fsharp/System/IDisposable/Overview/base1.fs b/snippets/fsharp/System/IDisposable/Overview/base1.fs
new file mode 100644
index 00000000000..11a1b13200c
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/base1.fs
@@ -0,0 +1,29 @@
+module base1
+
+//
+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
+
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/base2.fs b/snippets/fsharp/System/IDisposable/Overview/base2.fs
new file mode 100644
index 00000000000..c2ddca8baff
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/base2.fs
@@ -0,0 +1,29 @@
+module base2
+
+//
+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
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/calling1.fs b/snippets/fsharp/System/IDisposable/Overview/calling1.fs
new file mode 100644
index 00000000000..4beb81a697a
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/calling1.fs
@@ -0,0 +1,24 @@
+module calling1
+
+//
+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
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/calling2.fs b/snippets/fsharp/System/IDisposable/Overview/calling2.fs
new file mode 100644
index 00000000000..f66bcff2fb2
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/calling2.fs
@@ -0,0 +1,27 @@
+module calling2
+
+//
+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
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/derived1.fs b/snippets/fsharp/System/IDisposable/Overview/derived1.fs
new file mode 100644
index 00000000000..352c5a9c439
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/derived1.fs
@@ -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
+
+//
+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
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/fs.fsproj b/snippets/fsharp/System/IDisposable/Overview/fs.fsproj
new file mode 100644
index 00000000000..d8521d85271
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/fs.fsproj
@@ -0,0 +1,15 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs b/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs
new file mode 100644
index 00000000000..ea6ba931ea7
--- /dev/null
+++ b/snippets/fsharp/System/IDisposable/Overview/idisposabledispose.fs
@@ -0,0 +1,79 @@
+module idisposabledispose
+
+//
+// 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.
+[]
+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
+//
\ No newline at end of file
diff --git a/xml/System/IDisposable.xml b/xml/System/IDisposable.xml
index 8001af087ce..822034fc44a 100644
--- a/xml/System/IDisposable.xml
+++ b/xml/System/IDisposable.xml
@@ -64,7 +64,7 @@
## Using an object that implements IDisposable
If your app simply uses an object that implements the interface, you should call the object's 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 implementation in a `try`/`finally` block.
@@ -72,23 +72,25 @@
> Documentation for types that implement note that fact and include a reminder to call its implementation.
-### 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 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 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 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 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 if your type uses unmanaged resources directly or if you wish to use disposable resources yourself. The consumers of your type can call your implementation to free resources when the instance is no longer needed. To handle cases in which they fail to call , you should either use a class derived from to wrap the unmanaged resources, or you should override the method for a reference type. In either case, you use the 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 , see [the Dispose(bool) method overload](/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload).
@@ -109,11 +111,13 @@
The following code fragment reflects the dispose pattern for base classes. It assumes that your type does not override the 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 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:
@@ -127,6 +131,7 @@
The following code fragment reflects the dispose pattern for derived classes. It assumes that your type does not override the 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":::
@@ -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":::
]]>
@@ -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":::
]]>