diff --git a/snippets/fsharp/System/Object/Equals/equals2.fs b/snippets/fsharp/System/Object/Equals/equals2.fs
new file mode 100644
index 00000000000..fdfe5e871a4
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals2.fs
@@ -0,0 +1,54 @@
+module equals2
+
+//
+type Point(x, y) =
+ new () = Point(0, 0)
+ member _.X = x
+ member _.Y = y
+
+ override _.Equals(obj) =
+ //Check for null and compare run-time types.
+ match obj with
+ | :? Point as p ->
+ x = p.X && y = p.Y
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ (x <<< 2) ^^^ y
+
+ override _.ToString() =
+ $"Point({x}, {y})"
+
+type Point3D(x, y, z) =
+ inherit Point(x, y)
+ member _.Z = z
+
+ override _.Equals(obj) =
+ match obj with
+ | :? Point3D as pt3 ->
+ base.Equals(pt3 :> Point) && z = pt3.Z
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ (base.GetHashCode() <<< 2) ^^^ z
+
+ override _.ToString() =
+ $"Point({x}, {y}, {z})"
+
+let point2D = Point(5, 5)
+let point3Da = Point3D(5, 5, 2)
+let point3Db = Point3D(5, 5, 2)
+let point3Dc = Point3D(5, 5, -1)
+
+printfn $"{point2D} = {point3Da}: {point2D.Equals point3Da}"
+printfn $"{point2D} = {point3Db}: {point2D.Equals point3Db}"
+printfn $"{point3Da} = {point3Db}: {point3Da.Equals point3Db}"
+printfn $"{point3Da} = {point3Dc}: {point3Da.Equals point3Dc}"
+// The example displays the following output:
+// Point(5, 5) = Point(5, 5, 2): False
+// Point(5, 5) = Point(5, 5, 2): False
+// Point(5, 5, 2) = Point(5, 5, 2): True
+// Point(5, 5, 2) = Point(5, 5, -1): False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals3.fs b/snippets/fsharp/System/Object/Equals/equals3.fs
new file mode 100644
index 00000000000..4321df320d4
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals3.fs
@@ -0,0 +1,51 @@
+module equals3
+
+//
+type Point(x, y) =
+ member _.X = x
+ member _.Y = y
+
+ override _.Equals(obj) =
+ // Performs an equality check on two points (integer pairs).
+ match obj with
+ | :? Point as p ->
+ x = p.X && y = p.Y
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ (x, y).GetHashCode()
+
+type Rectangle(upLeftX, upLeftY, downRightX, downRightY) =
+ let a = Point(upLeftX, upLeftY)
+ let b = Point(downRightX, downRightY)
+
+ member _.UpLeft = a
+ member _.DownRight = b
+
+ override _.Equals(obj) =
+ // Perform an equality check on two rectangles (Point object pairs).
+ match obj with
+ | :? Rectangle as r ->
+ a.Equals(r.UpLeft) && b.Equals(r.DownRight)
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ (a, b).GetHashCode()
+
+ override _.ToString() =
+ $"Rectangle({a.X}, {a.Y}, {b.X}, {b.Y})"
+
+let r1 = Rectangle(0, 0, 100, 200)
+let r2 = Rectangle(0, 0, 100, 200)
+let r3 = Rectangle(0, 0, 150, 200)
+
+printfn $"{r1} = {r2}: {r1.Equals r2}"
+printfn $"{r1} = {r3}: {r1.Equals r3}"
+printfn $"{r2} = {r3}: {r2.Equals r3}"
+// The example displays the following output:
+// Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 100, 200): True
+// Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 150, 200): False
+// Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 150, 200): False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals4.fs b/snippets/fsharp/System/Object/Equals/equals4.fs
new file mode 100644
index 00000000000..ecde006fa16
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals4.fs
@@ -0,0 +1,48 @@
+module equals4
+
+//
+[]
+type Complex =
+ val mutable re: double
+ val mutable im: double
+
+ override this.Equals(obj) =
+ match obj with
+ | :? Complex as c when c = this -> true
+ | _ -> false
+
+ override this.GetHashCode() =
+ (this.re, this.im).GetHashCode()
+
+ override this.ToString() =
+ $"({this.re}, {this.im})"
+
+ static member op_Equality (x: Complex, y: Complex) =
+ x.re = y.re && x.im = y.im
+
+ static member op_Inequality (x: Complex, y: Complex) =
+ x = y |> not
+
+let mutable cmplx1 = Complex()
+let mutable cmplx2 = Complex()
+
+cmplx1.re <- 4.0
+cmplx1.im <- 1.0
+
+cmplx2.re <- 2.0
+cmplx2.im <- 1.0
+
+printfn $"{cmplx1} <> {cmplx2}: {cmplx1 <> cmplx2}"
+printfn $"{cmplx1} = {cmplx2}: {cmplx1.Equals cmplx2}"
+
+cmplx2.re <- 4.0
+
+printfn $"{cmplx1} = {cmplx2}: {cmplx1 = cmplx2}"
+printfn $"{cmplx1} = {cmplx2}: {cmplx1.Equals cmplx2}"
+
+// The example displays the following output:
+// (4, 1) <> (2, 1): True
+// (4, 1) = (2, 1): False
+// (4, 1) = (4, 1): True
+// (4, 1) = (4, 1): True
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals_ref.fs b/snippets/fsharp/System/Object/Equals/equals_ref.fs
new file mode 100644
index 00000000000..230ddffa411
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals_ref.fs
@@ -0,0 +1,27 @@
+module equals_ref
+
+//
+// Define a reference type that does not override Equals.
+type Person(name) =
+ override _.ToString() =
+ name
+
+let person1a = Person "John"
+let person1b = person1a
+let person2 = Person(string person1a)
+
+printfn "Calling Equals:"
+printfn $"person1a and person1b: {person1a.Equals person1b}"
+printfn $"person1a and person2: {person1a.Equals person2}"
+
+printfn "\nCasting to an Object and calling Equals:"
+printfn $"person1a and person1b: {(person1a :> obj).Equals(person1b :> obj)}"
+printfn $"person1a and person2: {(person1a :> obj).Equals(person2 :> obj)}"
+// The example displays the following output:
+// person1a and person1b: True
+// person1a and person2: False
+//
+// Casting to an Object and calling Equals:
+// person1a and person1b: True
+// person1a and person2: False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals_static2.fs b/snippets/fsharp/System/Object/Equals/equals_static2.fs
new file mode 100644
index 00000000000..b33668be44e
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals_static2.fs
@@ -0,0 +1,54 @@
+module equals_static2
+
+//
+open System
+
+// Class constructor
+type Dog(dogBreed) =
+ // Public property.
+ member _.Breed = dogBreed
+
+ override this.Equals(obj) =
+ match obj with
+ | :? Dog as dog when dog.Breed = this.Breed -> true
+ | _ -> false
+
+ override _.GetHashCode() =
+ dogBreed.GetHashCode()
+
+ override _.ToString() =
+ dogBreed
+
+let m1 = Dog "Alaskan Malamute"
+let m2 = Dog "Alaskan Malamute"
+let g1 = Dog "Great Pyrenees"
+let g2 = g1
+let d1 = Dog "Dalmation"
+let n1 = Unchecked.defaultof
+let n2 = Unchecked.defaultof
+
+printfn $"null = null: {Object.Equals(n1, n2)}"
+printfn $"null Reference Equals null: {Object.ReferenceEquals(n1, n2)}\n"
+
+printfn $"{g1} = {g2}: {Object.Equals(g1, g2)}"
+printfn $"{g1} Reference Equals {g2}: {Object.ReferenceEquals(g1, g2)}\n"
+
+printfn $"{m1} = {m2}: {Object.Equals(m1, m2)}"
+printfn $"{m1} Reference Equals {m2}: {Object.ReferenceEquals(m1, m2)}\n"
+
+printfn $"{m1} = {d1}: {Object.Equals(m1, d1)}"
+printfn $"{m1} Reference Equals {d1}: {Object.ReferenceEquals(m1, d1)}"
+
+// The example displays the following output:
+// null = null: True
+// null Reference Equals null: True
+//
+// Great Pyrenees = Great Pyrenees: True
+// Great Pyrenees Reference Equals Great Pyrenees: True
+//
+// Alaskan Malamute = Alaskan Malamute: True
+// Alaskan Malamute Reference Equals Alaskan Malamute: False
+//
+// Alaskan Malamute = Dalmation: False
+// Alaskan Malamute Reference Equals Dalmation: False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals_val1.fs b/snippets/fsharp/System/Object/Equals/equals_val1.fs
new file mode 100644
index 00000000000..1a3807394a7
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals_val1.fs
@@ -0,0 +1,14 @@
+module equals_val1
+
+//
+let value1 = 12uy
+let value2 = 12
+
+let object1 = value1 :> obj
+let object2 = value2 :> obj
+
+printfn $"{object1} ({object1.GetType().Name}) = {object2} ({object2.GetType().Name}): {object1.Equals object2}"
+
+// The example displays the following output:
+// 12 (Byte) = 12 (Int32): False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equals_val2.fs b/snippets/fsharp/System/Object/Equals/equals_val2.fs
new file mode 100644
index 00000000000..c41c65f0bb0
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equals_val2.fs
@@ -0,0 +1,24 @@
+module equals_val2
+
+//
+// Define a value type that does not override Equals.
+[]
+type Person(personName: string) =
+ override _.ToString() =
+ personName
+
+let person1 = Person "John"
+let person2 = Person "John"
+
+printfn "Calling Equals:"
+printfn $"{person1.Equals person2}"
+
+printfn $"\nCasting to an Object and calling Equals:"
+printfn $"{(person1 :> obj).Equals(person2 :> obj)}"
+// The example displays the following output:
+// Calling Equals:
+// True
+//
+// Casting to an Object and calling Equals:
+// True
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equalsoverride.fs b/snippets/fsharp/System/Object/Equals/equalsoverride.fs
new file mode 100644
index 00000000000..bf1d13a6fa8
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equalsoverride.fs
@@ -0,0 +1,27 @@
+module equalsoverride
+
+//
+open System
+
+type Person(name, id) =
+ member _.Name = name
+ member _.Id = id
+
+ override _.Equals(obj) =
+ match obj with
+ | :? Person as personObj ->
+ id.Equals personObj.Id
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ id.GetHashCode()
+
+let p1 = Person("John", "63412895")
+let p2 = Person("Jack", "63412895")
+printfn $"{p1.Equals p2}"
+printfn $"{Object.Equals(p1, p2)}"
+// The example displays the following output:
+// True
+// True
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/equalssb1.fs b/snippets/fsharp/System/Object/Equals/equalssb1.fs
new file mode 100644
index 00000000000..632f5045d98
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/equalssb1.fs
@@ -0,0 +1,23 @@
+module equalssb1
+
+//
+open System
+open System.Text
+
+let sb1 = StringBuilder "building a string..."
+let sb2 = StringBuilder "building a string..."
+
+printfn $"sb1.Equals(sb2): {sb1.Equals sb2}"
+printfn $"((Object) sb1).Equals(sb2): {(sb1 :> obj).Equals sb2}"
+
+printfn $"Object.Equals(sb1, sb2): {Object.Equals(sb1, sb2)}"
+
+let sb3 = StringBuilder "building a string..."
+printfn $"\nsb3.Equals(sb2): {sb3.Equals sb2}"
+// The example displays the following output:
+// sb1.Equals(sb2): True
+// ((Object) sb1).Equals(sb2): False
+// Object.Equals(sb1, sb2): False
+//
+// sb3.Equals(sb2): False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Equals/fs.fsproj b/snippets/fsharp/System/Object/Equals/fs.fsproj
new file mode 100644
index 00000000000..f0fc8297166
--- /dev/null
+++ b/snippets/fsharp/System/Object/Equals/fs.fsproj
@@ -0,0 +1,18 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Finalize/finalize1.fs b/snippets/fsharp/System/Object/Finalize/finalize1.fs
new file mode 100644
index 00000000000..21fc0efe2f8
--- /dev/null
+++ b/snippets/fsharp/System/Object/Finalize/finalize1.fs
@@ -0,0 +1,24 @@
+//
+open System.Diagnostics
+
+type ExampleClass() =
+ let sw = Stopwatch.StartNew()
+ do
+ printfn "Instantiated object"
+
+ member this.ShowDuration() =
+ printfn $"This instance of {this} has been in existence for {sw.Elapsed}"
+
+ override this.Finalize() =
+ printfn "Finalizing object"
+ sw.Stop()
+ printfn $"This instance of {this} has been in existence for {sw.Elapsed}"
+
+let ex = ExampleClass()
+ex.ShowDuration()
+// The example displays output like the following:
+// Instantiated object
+// This instance of ExampleClass has been in existence for 00:00:00.0011060
+// Finalizing object
+// This instance of ExampleClass has been in existence for 00:00:00.0036294
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Finalize/finalize_safe.fs b/snippets/fsharp/System/Object/Finalize/finalize_safe.fs
new file mode 100644
index 00000000000..748b9a94823
--- /dev/null
+++ b/snippets/fsharp/System/Object/Finalize/finalize_safe.fs
@@ -0,0 +1,123 @@
+module finalize_safe
+
+//
+open Microsoft.Win32.SafeHandles
+open System
+open System.ComponentModel
+open System.IO
+open System.Runtime.InteropServices
+
+// Windows API constants.
+let HKEY_CLASSES_ROOT = 0x80000000
+let ERROR_SUCCESS = 0
+let KEY_QUERY_VALUE = 1
+let KEY_SET_VALUE = 0x2
+let REG_SZ = 1u
+let MAX_PATH = 260
+
+// Windows API calls.
+[]
+extern int RegOpenKeyEx(nativeint hKey, string lpSubKey, int ulOptions, int samDesired, nativeint& phkResult)
+[]
+extern int RegQueryValueEx(nativeint hKey, string lpValueName, int lpReserved, uint& lpType, string lpData, uint& lpcbData)
+[]
+extern int RegSetValueEx(nativeint hKey, [] string lpValueName, int Reserved, uint dwType, [] string lpData, int cpData)
+[]
+extern int RegCloseKey(unativeint hKey)
+
+type FileAssociationInfo(fileExtension: string) =
+ // Private values.
+ let ext =
+ if fileExtension.StartsWith "." |> not then
+ "." + fileExtension
+ else
+ fileExtension
+ let mutable args = ""
+ let mutable hAppIdHandle = Unchecked.defaultof
+ let mutable hExtHandle = Unchecked.defaultof
+ let openCmd =
+ let mutable lpType = 0u
+ let mutable hExtension = 0n
+ // Get the file extension value.
+ let retVal = RegOpenKeyEx(nativeint HKEY_CLASSES_ROOT, fileExtension, 0, KEY_QUERY_VALUE, &hExtension)
+ if retVal <> ERROR_SUCCESS then
+ raise (Win32Exception retVal)
+ // Instantiate the first SafeRegistryHandle.
+ hExtHandle <- new SafeRegistryHandle(hExtension, true)
+
+ let appId = String(' ', MAX_PATH)
+ let mutable appIdLength = uint appId.Length
+ let retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, &lpType, appId, &appIdLength)
+ if retVal <> ERROR_SUCCESS then
+ raise (Win32Exception retVal)
+ // We no longer need the hExtension handle.
+ hExtHandle.Dispose()
+
+ // Determine the number of characters without the terminating null.
+ let appId = appId.Substring(0, int appIdLength / 2 - 1) + @"\shell\open\Command"
+
+ // Open the application identifier key.
+ let exeName = String(' ', MAX_PATH)
+ let exeNameLength = uint exeName.Length
+ let mutable hAppId = 0n
+ let retVal = RegOpenKeyEx(nativeint HKEY_CLASSES_ROOT, appId, 0, KEY_QUERY_VALUE ||| KEY_SET_VALUE, &hAppId)
+ if retVal <> ERROR_SUCCESS then
+ raise (Win32Exception retVal)
+
+ // Instantiate the second SafeRegistryHandle.
+ hAppIdHandle <- new SafeRegistryHandle(hAppId, true)
+
+ // Get the executable name for this file type.
+ let exePath = String(' ', MAX_PATH)
+ let mutable exePathLength = uint exePath.Length
+ let retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, &lpType, exePath, &exePathLength)
+ if retVal <> ERROR_SUCCESS then
+ raise (Win32Exception retVal)
+
+ // Determine the number of characters without the terminating null.
+ let exePath =
+ exePath.Substring(0, int exePathLength / 2 - 1)
+ // Remove any environment strings.
+ |> Environment.ExpandEnvironmentVariables
+
+ let position = exePath.IndexOf '%'
+ if position >= 0 then
+ args <- exePath.Substring position
+ // Remove command line parameters ('%0', etc.).
+ exePath.Substring(0, position).Trim()
+ else
+ exePath
+
+ member _.Extension =
+ ext
+
+ member _.Open
+ with get () = openCmd
+ and set (value) =
+ if hAppIdHandle.IsInvalid || hAppIdHandle.IsClosed then
+ raise (InvalidOperationException "Cannot write to registry key.")
+ if not (File.Exists value) then
+ raise (FileNotFoundException $"'{value}' does not exist")
+
+ let cmd = value + " %1"
+ let retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, REG_SZ, value, value.Length + 1)
+ if retVal <> ERROR_SUCCESS then
+ raise (Win32Exception retVal)
+
+ member this.Dispose() =
+ this.Dispose true
+ GC.SuppressFinalize this
+
+ member _.Dispose(disposing) =
+ // Ordinarily, we release unmanaged resources here
+ // but all are wrapped by safe handles.
+
+ // Release disposable objects.
+ if disposing then
+ if hExtHandle <> null then hExtHandle.Dispose()
+ if hAppIdHandle <> null then hAppIdHandle.Dispose()
+
+ interface IDisposable with
+ member this.Dispose() =
+ this.Dispose()
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Finalize/fs.fsproj b/snippets/fsharp/System/Object/Finalize/fs.fsproj
new file mode 100644
index 00000000000..7dfbd39fc56
--- /dev/null
+++ b/snippets/fsharp/System/Object/Finalize/fs.fsproj
@@ -0,0 +1,11 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetHashCode/direct1.fs b/snippets/fsharp/System/Object/GetHashCode/direct1.fs
new file mode 100644
index 00000000000..49f21a4c4c2
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetHashCode/direct1.fs
@@ -0,0 +1,38 @@
+module direct1
+
+//
+open System
+
+[]
+type Number(value: int) =
+ member _.Value = value
+
+ override _.Equals(obj) =
+ match obj with
+ | :? Number as n ->
+ n.Value = value
+ | _ -> false
+
+ override _.GetHashCode() =
+ value
+
+ override _.ToString() =
+ string value
+
+let rnd = Random()
+for _ = 0 to 9 do
+ let randomN = rnd.Next(Int32.MinValue, Int32.MaxValue)
+ let n = Number randomN
+ printfn $"n = {n,12}, hash code = {n.GetHashCode(),12}"
+// The example displays output like the following:
+// n = -634398368, hash code = -634398368
+// n = 2136747730, hash code = 2136747730
+// n = -1973417279, hash code = -1973417279
+// n = 1101478715, hash code = 1101478715
+// n = 2078057429, hash code = 2078057429
+// n = -334489950, hash code = -334489950
+// n = -68958230, hash code = -68958230
+// n = -379951485, hash code = -379951485
+// n = -31553685, hash code = -31553685
+// n = 2105429592, hash code = 2105429592
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetHashCode/fs.fsproj b/snippets/fsharp/System/Object/GetHashCode/fs.fsproj
new file mode 100644
index 00000000000..6536eab40cf
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetHashCode/fs.fsproj
@@ -0,0 +1,13 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetHashCode/shift1.fs b/snippets/fsharp/System/Object/GetHashCode/shift1.fs
new file mode 100644
index 00000000000..76c44fe52a7
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetHashCode/shift1.fs
@@ -0,0 +1,50 @@
+module shift1
+
+//
+open System
+
+[]
+type Point(x: int, y: int) =
+ member _.X = x
+ member _.Y = y
+ override _.Equals(obj) =
+ match obj with
+ | :? Point as p ->
+ x = p.X && y = p.Y
+ | _ ->
+ false
+
+ override this.GetHashCode() =
+ this.ShiftAndWrap(x.GetHashCode(), 2) ^^^ y.GetHashCode()
+
+ member _.ShiftAndWrap(value, positions) =
+ let positions = positions &&& 0x1F
+
+ // Save the existing bit pattern, but interpret it as an unsigned integer.
+ let number = BitConverter.ToUInt32(BitConverter.GetBytes value, 0)
+ // Preserve the bits to be discarded.
+ let wrapped = number >>> (32 - positions)
+ // Shift and wrap the discarded bits.
+ BitConverter.ToInt32(BitConverter.GetBytes((number <<< positions) ||| wrapped), 0)
+
+let pt = Point(5, 8)
+printfn $"{pt.GetHashCode()}"
+
+let pt2 = Point(8, 5)
+printfn $"{pt2.GetHashCode()}"
+// The example displays the following output:
+// 28
+// 37
+//
+
+//
+let shiftAndWrap (value: int) positions =
+ let positions = positions &&& 0x1F
+
+ // Save the existing bit pattern, but interpret it as an unsigned integer.
+ let number = BitConverter.ToUInt32(BitConverter.GetBytes value, 0)
+ // Preserve the bits to be discarded.
+ let wrapped = number >>> (32 - positions)
+ // Shift and wrap the discarded bits.
+ BitConverter.ToInt32(BitConverter.GetBytes((number <<< positions) ||| wrapped), 0)
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetHashCode/xor1.fs b/snippets/fsharp/System/Object/GetHashCode/xor1.fs
new file mode 100644
index 00000000000..98a461d9595
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetHashCode/xor1.fs
@@ -0,0 +1,28 @@
+module xor1
+
+//
+// A type that represents a 2-D point.
+[]
+type Point(x: int, y: int) =
+ member _.X = x
+ member _.Y = y
+
+ override _.Equals(obj) =
+ match obj with
+ | :? Point as p ->
+ x = p.X && y = p.Y
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ x ^^^ y
+
+let pt = Point(5, 8)
+printfn $"{pt.GetHashCode()}"
+
+let pt2 = Point(8, 5)
+printfn $"{pt.GetHashCode()}"
+// The example displays the following output:
+// 13
+// 13
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetHashCode/xor2.fs b/snippets/fsharp/System/Object/GetHashCode/xor2.fs
new file mode 100644
index 00000000000..c83ecf87704
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetHashCode/xor2.fs
@@ -0,0 +1,27 @@
+module xor2
+
+//
+[]
+type Point(x: int, y: int) =
+ member _.X = x
+ member _.Y = y
+
+ override _.Equals(obj) =
+ match obj with
+ | :? Point as p ->
+ x = p.X && y = p.Y
+ | _ ->
+ false
+
+ override _.GetHashCode() =
+ (x, y).GetHashCode()
+
+let pt = Point(5, 8)
+printfn $"{pt.GetHashCode()}"
+
+let pt2 = Point(8, 5)
+printfn $"{pt2.GetHashCode()}"
+// The example displays the following output:
+// 173
+// 269
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetType/GetTypeEx2.fs b/snippets/fsharp/System/Object/GetType/GetTypeEx2.fs
new file mode 100644
index 00000000000..ecaa6a0e579
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetType/GetTypeEx2.fs
@@ -0,0 +1,30 @@
+module GetTypeEx2
+
+//
+let values: obj[] =
+ [| 12; 10653L; 12uy
+ -5y; 16.3; "string" |]
+
+for value in values do
+ let t = value.GetType()
+ if t.Equals typeof then
+ printfn $"{value} is an unsigned byte."
+ elif t.Equals typeof then
+ printfn $"{value} is a signed byte."
+ elif t.Equals typeof then
+ printfn $"{value} is a 32-bit integer."
+ elif t.Equals typeof then
+ printfn $"{value} is a 64-bit integer."
+ elif t.Equals typeof then
+ printfn $"{value} is a double-precision floating point."
+ else
+ printfn $"'{value}' is another data type."
+
+// The example displays the following output:
+// 12 is a 32-bit integer.
+// 10653 is a 32-bit integer.
+// 12 is an unsigned byte.
+// -5 is a signed byte.
+// 16.3 is a double-precision floating point.
+// 'string' is another data type.
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetType/fs.fsproj b/snippets/fsharp/System/Object/GetType/fs.fsproj
new file mode 100644
index 00000000000..fea8d55653f
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetType/fs.fsproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetType/gettype.fs b/snippets/fsharp/System/Object/GetType/gettype.fs
new file mode 100644
index 00000000000..486e4cffc94
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetType/gettype.fs
@@ -0,0 +1,23 @@
+module gettype
+
+//
+type MyBaseClass() = class end
+
+type MyDerivedClass() =
+ inherit MyBaseClass()
+
+let myBase = MyBaseClass()
+let myDerived = MyDerivedClass()
+let o: obj = myDerived
+let b: MyBaseClass = myDerived
+
+printfn $"mybase: Type is {myBase.GetType()}"
+printfn $"myDerived: Type is {myDerived.GetType()}"
+printfn $"object o = myDerived: Type is {o.GetType()}"
+printfn $"MyBaseClass b = myDerived: Type is {b.GetType()}"
+// The example displays the following output:
+// mybase: Type is MyBaseClass
+// myDerived: Type is MyDerivedClass
+// object o = myDerived: Type is MyDerivedClass
+// MyBaseClass b = myDerived: Type is MyDerivedClass
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/GetType/gettype1.fs b/snippets/fsharp/System/Object/GetType/gettype1.fs
new file mode 100644
index 00000000000..1a1322ebeb7
--- /dev/null
+++ b/snippets/fsharp/System/Object/GetType/gettype1.fs
@@ -0,0 +1,15 @@
+module gettype1
+
+//
+open System
+
+let n1 = 12
+let n2 = 82
+let n3 = 12L
+
+printfn $"n1 and n2 are the same type: {Object.ReferenceEquals(n1.GetType(), n2.GetType())}"
+printfn $"n1 and n3 are the same type: {Object.ReferenceEquals(n1.GetType(), n3.GetType())}"
+// The example displays the following output:
+// n1 and n2 are the same type: True
+// n1 and n3 are the same type: False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/MemberwiseClone/fs.fsproj b/snippets/fsharp/System/Object/MemberwiseClone/fs.fsproj
new file mode 100644
index 00000000000..2865ecbbc23
--- /dev/null
+++ b/snippets/fsharp/System/Object/MemberwiseClone/fs.fsproj
@@ -0,0 +1,10 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/MemberwiseClone/memberwiseclone1.fs b/snippets/fsharp/System/Object/MemberwiseClone/memberwiseclone1.fs
new file mode 100644
index 00000000000..0b4626c055a
--- /dev/null
+++ b/snippets/fsharp/System/Object/MemberwiseClone/memberwiseclone1.fs
@@ -0,0 +1,90 @@
+//
+open System
+
+type IdInfo(IdNumber) =
+ member val IdNumber = IdNumber with get, set
+
+type Person() =
+ []
+ val mutable public Age: int
+ []
+ val mutable public Name: string
+ []
+ val mutable public IdInfo: IdInfo
+
+ member this.ShallowCopy() =
+ this.MemberwiseClone() :?> Person
+
+ member this.DeepCopy() =
+ let other = this.MemberwiseClone() :?> Person
+ other.IdInfo <- IdInfo this.IdInfo.IdNumber
+ other.Name <- String.Copy this.Name
+ other
+
+let displayValues (p: Person) =
+ printfn $" Name: {p.Name:s}, Age: {p.Age:d}"
+ printfn $" Value: {p.IdInfo.IdNumber:d}"
+
+// Create an instance of Person and assign values to its fields.
+let p1 = Person()
+p1.Age <- 42
+p1.Name <- "Sam"
+p1.IdInfo <- IdInfo 6565
+
+// Perform a shallow copy of p1 and assign it to p2.
+let p2 = p1.ShallowCopy()
+
+// Display values of p1, p2
+printfn "Original values of p1 and p2:"
+printfn " p1 instance values: "
+displayValues p1
+printfn " p2 instance values:"
+displayValues p2
+
+// Change the value of p1 properties and display the values of p1 and p2.
+p1.Age <- 32
+p1.Name <- "Frank"
+p1.IdInfo.IdNumber <- 7878
+printfn "\nValues of p1 and p2 after changes to p1:"
+printfn " p1 instance values: "
+displayValues p1
+printfn " p2 instance values:"
+displayValues p2
+
+// Make a deep copy of p1 and assign it to p3.
+let p3 = p1.DeepCopy()
+// Change the members of the p1 class to new values to show the deep copy.
+p1.Name <- "George"
+p1.Age <- 39
+p1.IdInfo.IdNumber <- 8641
+printfn "\nValues of p1 and p3 after changes to p1:"
+printfn " p1 instance values: "
+displayValues p1
+printfn " p3 instance values:"
+displayValues p3
+// The example displays the following output:
+// Original values of p1 and p2:
+// p1 instance values:
+// Name: Sam, Age: 42
+// Value: 6565
+// p2 instance values:
+// Name: Sam, Age: 42
+// Value: 6565
+//
+// Values of p1 and p2 after changes to p1:
+// p1 instance values:
+// Name: Frank, Age: 32
+// Value: 7878
+// p2 instance values:
+// Name: Sam, Age: 42
+// Value: 7878
+//
+// Values of p1 and p3 after changes to p1:
+// p1 instance values:
+// Name: George, Age: 39
+// Value: 8641
+// p3 instance values:
+// Name: Frank, Age: 32
+// Value: 7878
+//
+// Copied from /snippets/csharp/System/Object/MemberwiseClone/memberwiseclone1.cs
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Overview/ObjectX.fs b/snippets/fsharp/System/Object/Overview/ObjectX.fs
new file mode 100644
index 00000000000..5f69d3b097b
--- /dev/null
+++ b/snippets/fsharp/System/Object/Overview/ObjectX.fs
@@ -0,0 +1,70 @@
+//
+open System
+
+// The Point class is derived from System.Object.
+type Point(x, y) =
+ member _.X = x
+ member _.Y = y
+ //
+ override _.Equals obj =
+ // If this and obj do not refer to the same type, then they are not equal.
+ match obj with
+ | :? Point as other ->
+ // Return true if x and y fields match.
+ x = other.X && y = other.Y
+ | _ ->
+ false
+ //
+
+ //
+ // Return the XOR of the x and y fields.
+ override _.GetHashCode() =
+ x ^^^ y
+ //
+
+ //
+ // Return the point's value as a string.
+ override _.ToString() =
+ $"({x}, {y})"
+ //
+
+ //
+ // Return a copy of this point object by making a simple field copy.
+ member this.Copy() =
+ this.MemberwiseClone() :?> Point
+ //
+
+// Construct a Point object.
+let p1 = Point(1,2)
+
+// Make another Point object that is a copy of the first.
+let p2 = p1.Copy()
+
+// Make another variable that references the first Point object.
+let p3 = p1
+
+//
+// The line below displays false because p1 and p2 refer to two different objects.
+printfn $"{Object.ReferenceEquals(p1, p2)}"
+//
+
+//
+// The line below displays true because p1 and p2 refer to two different objects that have the same value.
+printfn $"{Object.Equals(p1, p2)}"
+//
+
+// The line below displays true because p1 and p3 refer to one object.
+printfn $"{Object.ReferenceEquals(p1, p3)}"
+
+//
+// The line below displays: p1's value is: (1, 2)
+printfn $"p1's value is: {p1.ToString()}"
+//
+// This code example produces the following output:
+//
+// False
+// True
+// True
+// p1's value is: (1, 2)
+//
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/Overview/fs.fsproj b/snippets/fsharp/System/Object/Overview/fs.fsproj
new file mode 100644
index 00000000000..4e57f707fd7
--- /dev/null
+++ b/snippets/fsharp/System/Object/Overview/fs.fsproj
@@ -0,0 +1,10 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ReferenceEquals/fs.fsproj b/snippets/fsharp/System/Object/ReferenceEquals/fs.fsproj
new file mode 100644
index 00000000000..a6bba73fbe5
--- /dev/null
+++ b/snippets/fsharp/System/Object/ReferenceEquals/fs.fsproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ReferenceEquals/referenceequals.fs b/snippets/fsharp/System/Object/ReferenceEquals/referenceequals.fs
new file mode 100644
index 00000000000..267fc5074f4
--- /dev/null
+++ b/snippets/fsharp/System/Object/ReferenceEquals/referenceequals.fs
@@ -0,0 +1,19 @@
+module referenceequals
+
+open System
+
+//
+let o: obj = null
+let mutable p: obj = null
+let q = obj ()
+
+printfn $"{Object.ReferenceEquals(o, p)}"
+p <- q
+printfn $"{Object.ReferenceEquals(p, q)}"
+printfn $"{Object.ReferenceEquals(o, p)}"
+
+// This code produces the following output:
+// True
+// True
+// False
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ReferenceEquals/referenceequals4.fs b/snippets/fsharp/System/Object/ReferenceEquals/referenceequals4.fs
new file mode 100644
index 00000000000..e29c904ac23
--- /dev/null
+++ b/snippets/fsharp/System/Object/ReferenceEquals/referenceequals4.fs
@@ -0,0 +1,13 @@
+module referenceequals4
+
+open System
+
+//
+let int1 = 3
+printfn $"{Object.ReferenceEquals(int1, int1)}"
+printfn $"{int1.GetType().IsValueType}"
+
+// The example displays the following output:
+// False
+// True
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ReferenceEquals/referenceequalsa.fs b/snippets/fsharp/System/Object/ReferenceEquals/referenceequalsa.fs
new file mode 100644
index 00000000000..6141e661ada
--- /dev/null
+++ b/snippets/fsharp/System/Object/ReferenceEquals/referenceequalsa.fs
@@ -0,0 +1,22 @@
+module referenceequalsa
+
+//
+open System
+
+let s1 = "String1"
+let s2 = "String1"
+printfn $"s1 = s2: {Object.ReferenceEquals(s1, s2)}"
+printfn $"""{s1} interned: {if String.IsNullOrEmpty(String.IsInterned s1) then "No" else "Yes"}"""
+
+let suffix = "A"
+let s3 = "String" + suffix
+let s4 = "String" + suffix
+printfn $"s3 = s4: {Object.ReferenceEquals(s3, s4)}"
+printfn $"""{s3} interned: {if String.IsNullOrEmpty(String.IsInterned s3) then "No" else "Yes"}"""
+
+// The example displays the following output:
+// s1 = s2: True
+// String1 interned: Yes
+// s3 = s4: False
+// StringA interned: No
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/array1.fs b/snippets/fsharp/System/Object/ToString/array1.fs
new file mode 100644
index 00000000000..c9ab8a253ba
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/array1.fs
@@ -0,0 +1,13 @@
+module array1
+
+//
+let values = [| 1; 2; 4; 8; 16; 32; 64; 128 |]
+printfn $"{values}"
+
+let list = ResizeArray values
+printfn $"{list}"
+
+// The example displays the following output:
+// System.Int32[]
+// System.Collections.Generic.List`1[System.Int32]
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/customize1.fs b/snippets/fsharp/System/Object/ToString/customize1.fs
new file mode 100644
index 00000000000..24e73763274
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/customize1.fs
@@ -0,0 +1,25 @@
+module customize1
+
+//
+open System
+open System.Collections.Generic
+
+type CList<'T>() =
+ inherit ResizeArray<'T>()
+
+ override this.ToString() =
+ let mutable retVal = String.Empty
+ for item in this do
+ if String.IsNullOrEmpty retVal then
+ retVal <- retVal + string item
+ else
+ retVal <- retVal + $", {item}"
+ retVal
+
+let list2 = CList()
+list2.Add 1000
+list2.Add 2000
+printfn $"{list2}"
+// The example displays the following output:
+// 1000, 2000
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/customize2.fs b/snippets/fsharp/System/Object/ToString/customize2.fs
new file mode 100644
index 00000000000..b84893fde8c
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/customize2.fs
@@ -0,0 +1,32 @@
+module customize2
+
+//
+open System
+open System.Collections.Generic
+
+type List<'T> with
+ member this.ToString2<'T>() =
+ let mutable retVal = String.Empty
+ for item in this do
+ retVal <- retVal + $"""{if String.IsNullOrEmpty retVal then "" else ", "}{item}"""
+ if String.IsNullOrEmpty retVal then "{}" else "{ " + retVal + " }"
+
+ member this.ToString<'T>(fmt: string) =
+ let mutable retVal = String.Empty
+ for item in this do
+ match box item with
+ | :? IFormattable as ifmt ->
+ retVal <- retVal + $"""{if String.IsNullOrEmpty retVal then "" else ", "}{ifmt.ToString(fmt, null)}"""
+ | _ ->
+ retVal <- retVal + this.ToString2()
+ if String.IsNullOrEmpty retVal then "{}" else "{ " + retVal + " }"
+
+let list = ResizeArray()
+list.Add 1000
+list.Add 2000
+printfn $"{list.ToString2()}"
+printfn $"""{list.ToString "N0"}"""
+// The example displays the following output:
+// { 1000, 2000 }
+// { 1,000, 2,000 }
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/fs.fsproj b/snippets/fsharp/System/Object/ToString/fs.fsproj
new file mode 100644
index 00000000000..7759a956b1f
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/fs.fsproj
@@ -0,0 +1,17 @@
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/tostring1.fs b/snippets/fsharp/System/Object/ToString/tostring1.fs
new file mode 100644
index 00000000000..85ffddd04a5
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/tostring1.fs
@@ -0,0 +1,10 @@
+module tostring1
+
+//
+let obj = obj ()
+printfn $"{obj.ToString()}"
+// printfn $"{obj}" // Equivalent
+
+// The example displays the following output:
+// System.Object
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/tostring2.fs b/snippets/fsharp/System/Object/ToString/tostring2.fs
new file mode 100644
index 00000000000..87dba31ebcf
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/tostring2.fs
@@ -0,0 +1,10 @@
+module tostring2
+
+//
+type Object1() = class end
+
+let obj1 = Object1()
+printfn $"{obj1.ToString()}"
+// The example displays the following output:
+// Examples.Object1
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/tostring3.fs b/snippets/fsharp/System/Object/ToString/tostring3.fs
new file mode 100644
index 00000000000..28db439aa30
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/tostring3.fs
@@ -0,0 +1,13 @@
+module tostring3
+
+//
+type Object2(value: obj) =
+ inherit obj ()
+ override _.ToString() =
+ base.ToString() + ": " + value.ToString()
+
+let obj2 = Object2 'a'
+printfn $"{obj2.ToString()}"
+// The example displays the following output:
+// Object2: a
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/tostringoverload1.fs b/snippets/fsharp/System/Object/ToString/tostringoverload1.fs
new file mode 100644
index 00000000000..2c0cc99c7da
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/tostringoverload1.fs
@@ -0,0 +1,38 @@
+module tostringoverload1
+
+//
+open System
+
+type Automobile(model: string, year: int, doors: int, cylinders: string) =
+ member _.Doors = doors
+ member _.Model = model
+ member _.Year = year
+ member _.Cylinders = cylinders
+
+ override this.ToString() =
+ this.ToString "G"
+
+ member _.ToString(fmt) =
+ let fmt =
+ if String.IsNullOrEmpty fmt then "G"
+ else fmt.ToUpperInvariant()
+
+ match fmt with
+ | "G" ->
+ $"{year} {model}"
+ | "D" ->
+ $"{year} {model}, {doors} dr."
+ | "C" ->
+ $"{year} {model}, {cylinders}"
+ | "A" ->
+ $"{year} {model}, {doors} dr. {cylinders}"
+ | _ ->
+ raise (ArgumentException $"'{fmt}' is an invalid format string")
+
+let auto = Automobile("Lynx", 2016, 4, "V8")
+printfn $"{auto}"
+printfn $"""{auto.ToString "A"}"""
+// The example displays the following output:
+// 2016 Lynx
+// 2016 Lynx, 4 dr. V8
+//
\ No newline at end of file
diff --git a/snippets/fsharp/System/Object/ToString/tostringoverload2.fs b/snippets/fsharp/System/Object/ToString/tostringoverload2.fs
new file mode 100644
index 00000000000..c6e7e3e993a
--- /dev/null
+++ b/snippets/fsharp/System/Object/ToString/tostringoverload2.fs
@@ -0,0 +1,18 @@
+module tostringoverload2
+
+//
+open System.Globalization
+
+let cultureNames =
+ [| "en-US"; "en-GB"; "fr-FR"; "hr-HR"; "ja-JP" |]
+let value = 1603.49m
+for cultureName in cultureNames do
+ let culture = CultureInfo cultureName
+ printfn $"""{culture.Name}: {value.ToString("C2", culture)}"""
+// The example displays the following output:
+// en-US: $1,603.49
+// en-GB: £1,603.49
+// fr-FR: 1 603,49 €
+// hr-HR: 1.603,49 kn
+// ja-JP: ¥1,603.49
+//
\ No newline at end of file
diff --git a/xml/System/Object.xml b/xml/System/Object.xml
index 56180ca6545..23df859495b 100644
--- a/xml/System/Object.xml
+++ b/xml/System/Object.xml
@@ -83,6 +83,7 @@
The following example defines a Point type derived from the class and overrides many of the virtual methods of the class. In addition, the example shows how to call many of the static and instance methods of the class.
:::code language="csharp" source="~/snippets/csharp/System/Object/Overview/ObjectX.cs" interactive="try-dotnet" id="snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Overview/ObjectX.fs" id="snippet1":::
:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR/ObjectX/cpp/ObjectX.cpp" id="snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR/ObjectX/vb/objectX.vb" id="snippet1":::
@@ -214,6 +215,7 @@
- If the current instance is a reference type, the method tests for reference equality, and a call to the method is equivalent to a call to the method. Reference equality means that the object variables that are compared refer to the same object. The following example illustrates the result of such a comparison. It defines a `Person` class, which is a reference type, and calls the `Person` class constructor to instantiate two new `Person` objects, `person1a` and `person2`, which have the same value. It also assigns `person1a` to another object variable, `person1b`. As the output from the example shows, `person1a` and `person1b` are equal because they reference the same object. However, `person1a` and `person2` are not equal, although they have the same value.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals_ref.cs" interactive="try-dotnet" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals_ref.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equals_ref.vb" id="Snippet2":::
- If the current instance is a value type, the method tests for value equality. Value equality means the following:
@@ -221,11 +223,13 @@
- The two objects are of the same type. As the following example shows, a object that has a value of 12 does not equal an object that has a value of 12, because the two objects have different run-time types.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals_val1.cs" interactive="try-dotnet-method" id="Snippet3":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals_val1.fs" id="Snippet3":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equals_val1.vb" id="Snippet3":::
- The values of the public and private fields of the two objects are equal. The following example tests for value equality. It defines a `Person` structure, which is a value type, and calls the `Person` class constructor to instantiate two new `Person` objects, `person1` and `person2`, which have the same value. As the output from the example shows, although the two object variables refer to different objects, `person1` and `person2` are equal because they have the same value for the private `personName` field.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals_val2.cs" id="Snippet4":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals_val2.fs" id="Snippet4":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equals_val2.vb" id="Snippet4":::
Because the class is the base class for all types in the .NET Framework, the method provides the default equality comparison for all other types. However, types often override the method to implement value equality. For more information, see the Notes for Callers and Notes for Inheritors sections.
@@ -242,6 +246,7 @@
The following example provides an illustration. It instantiates three objects with identical strings, and then makes four calls to `Equals` methods. The first method call returns `true`, and the remaining three return `false`.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equalssb1.cs" interactive="try-dotnet" id="Snippet5":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equalssb1.fs" id="Snippet5":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equalssb1.vb" id="Snippet5":::
In the first case, the strongly typed method overload, which tests for value equality, is called. Because the strings assigned to the two objects are equal, the method returns `true`. However, does not override . Because of this, when the object is cast to an , when a instance is assigned to a variable of type , and when the method is passed two objects, the default method is called. Because is a reference type, this is equivalent to passing the two objects to the method. Although all three objects contain identical strings, they refer to three distinct objects. As a result, these three method calls return `false`.
@@ -264,6 +269,7 @@
The following example shows how to override the method to test for value equality. It overrides the method for the `Person` class. If `Person` accepted its base class implementation of equality, two `Person` objects would be equal only if they referenced a single object. However, in this case, two `Person` objects are equal if they have the same value for the `Person.Id` property.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equalsoverride.cs" id="Snippet6":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equalsoverride.fs" id="Snippet6":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equalsoverride.vb" id="Snippet6":::
In addition to overriding , you can implement the interface to provide a strongly typed test for equality.
@@ -318,6 +324,7 @@
The following example shows a `Point` class that overrides the method to provide value equality, and a `Point3D` class that is derived from `Point`. Because `Point` overrides to test for value equality, the method is not called. However, `Point3D.Equals` calls `Point.Equals` because `Point` implements in a manner that provides value equality.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals2.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals2.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR/ECMA-System.Object.Equals2/VB/equals2.vb" id="Snippet1":::
The `Point.Equals` method checks to make sure that the `obj` argument is not **null** and that it references an instance of the same type as this object. If either check fails, the method returns `false`.
@@ -329,11 +336,13 @@
The following example defines a `Rectangle` class that internally implements a rectangle as two `Point` objects. The `Rectangle` class also overrides to provide for value equality.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals3.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals3.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR/ECMA-System.Object.Equals3/VB/equals3.vb" id="Snippet1":::
Some languages such as C# and Visual Basic support operator overloading. When a type overloads the equality operator, it must also override the method to provide the same functionality. This is typically accomplished by writing the method in terms of the overloaded equality operator, as in the following example.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals4.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals4.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR/ECMA-System.Object.Equals4/vb/equals4.vb" id="Snippet1":::
Because `Complex` is a value type, it cannot be derived from. Therefore, the override to method need not call to determine the precise run-time type of each object, but can instead use the `is` operator in C# or the `TypeOf` operator in Visual Basic to check the type of the `obj` parameter.
@@ -418,6 +427,7 @@
The following example illustrates the method and compares it with the method.
:::code language="csharp" source="~/snippets/csharp/System/Object/Equals/equals_static2.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Equals/equals_static2.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.equals/vb/equals_static2.vb" id="Snippet1":::
]]>
@@ -559,6 +569,7 @@ and the interface. The method. It defines a `FileAssociation` class that wraps registry information about the application that handles files with a particular file extension. The two registry handles returned as `out` parameters by Windows [RegOpenKeyEx](/windows/win32/api/winreg/nf-winreg-regopenkeyexa) function calls are passed to the constructor. The type's protected `Dispose` method then calls the `SafeRegistryHandle.Dispose` method to free these two handles.
:::code language="csharp" source="~/snippets/csharp/System/Object/Finalize/finalize_safe.cs" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Finalize/finalize_safe.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.finalize/vb/finalize_safe.vb" id="Snippet2":::
@@ -567,6 +578,7 @@ and the interface. The method is called when an object that overrides is destroyed. Note that, in a production application, the method would be overridden to release unmanaged resources held by the object. Also note that the C# example provides a destructor instead of overriding the method.
:::code language="csharp" source="~/snippets/csharp/System/Object/Finalize/finalize1.cs" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/Finalize/finalize1.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.finalize/vb/finalize1.vb" id="Snippet1":::
For an additional example that overrides the method, see the method.
@@ -667,26 +679,31 @@ and the interface. The type is to simply return that value. The following example shows such an implementation for a `Number` structure.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetHashCode/direct1.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetHashCode/direct1.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gethashcode/vb/direct1.vb" id="Snippet1":::
Frequently, a type has multiple data fields that can participate in generating the hash code. One way to generate a hash code is to combine these fields using an `XOR (eXclusive OR)` operation, as shown in the following example.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetHashCode/xor1.cs" interactive="try-dotnet" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetHashCode/xor1.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gethashcode/vb/xor1.vb" id="Snippet2":::
The previous example returns the same hash code for (n1, n2) and (n2, n1), and so may generate more collisions than are desirable. A number of solutions are available so that hash codes in these cases are not identical. One is to return the hash code of a `Tuple` object that reflects the order of each field. The following example shows a possible implementation that uses the class. Note, though, that the performance overhead of instantiating a `Tuple` object may significantly impact the overall performance of an application that stores large numbers of objects in hash tables.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetHashCode/xor2.cs" interactive="try-dotnet" id="Snippet3":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetHashCode/xor2.fs" id="Snippet3":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gethashcode/vb/xor2.vb" id="Snippet3":::
A second alternative solution involves weighting the individual hash codes by left-shifting the hash codes of successive fields by two or more bits. Optimally, bits shifted beyond bit 31 should wrap around rather than be discarded. Since bits are discarded by the left-shift operators in both C# and Visual Basic, this requires creating a left shift-and-wrap method like the following:
:::code language="csharp" source="~/snippets/csharp/System/Object/GetHashCode/shift1.cs" id="Snippet4":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetHashCode/shift1.fs" id="Snippet4":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gethashcode/vb/shift1.vb" id="Snippet4":::
The following example then uses this shift-and-wrap method to compute the hash code of the `Point` structure used in the previous examples.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetHashCode/shift1.cs" interactive="try-dotnet" id="Snippet5":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetHashCode/shift1.fs" id="Snippet5":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gethashcode/vb/shift1.vb" id="Snippet5":::
]]>
@@ -799,6 +816,7 @@ and the interface. The method with the method to determine whether one numeric value is the same type as two other numeric values.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetType/gettype1.cs" interactive="try-dotnet-method" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetType/gettype1.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gettype/vb/gettype1.vb" id="Snippet1":::
> [!NOTE]
@@ -807,6 +825,7 @@ and the interface. The method is inherited by all types that derive from . This means that, in addition to using your own language's comparison keyword, you can use the method to determine the type of a particular object, as the following example shows.
:::code language="csharp" source="~/snippets/csharp/System/Object/GetType/GetTypeEx2.cs" interactive="try-dotnet-method" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/GetType/GetTypeEx2.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.gettype/vb/GetTypeEx2.vb" id="Snippet2":::
The object exposes the metadata associated with the class of the current .
@@ -819,6 +838,7 @@ and the interface. The
@@ -895,6 +915,7 @@ and the interface. The method. It defines a `ShallowCopy` method that calls the method to perform a shallow copy operation on a `Person` object. It also defines a `DeepCopy` method that performs a deep copy operation on a `Person` object.
:::code language="csharp" source="~/snippets/csharp/System/Object/MemberwiseClone/memberwiseclone1.cs" interactive="try-dotnet" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/MemberwiseClone/memberwiseclone1.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.memberwiseclone/vb/memberwiseclone1.vb" id="Snippet1":::
In this example, the `Person.IdInfo` property returns an `IdInfo` object. As the output from the example shows, when a `Person` object is cloned by calling the method, the cloned `Person` object is an independent copy of the original object, except that they share the same `Person.IdInfo` object reference. As a result, modifying the clone's `Person.IdInfo` property changes the original object's `Person.IdInfo` property. On the other hand, when a deep copy operation is performed, the cloned `Person` object, including its `Person.IdInfo` property, can be modified without affecting the original object.
@@ -970,6 +991,7 @@ and the interface. The method. This means that if both `objA` and `objB` represent the same instance of a value type, the method nevertheless returns `false`, as the following example shows.
:::code language="csharp" source="~/snippets/csharp/System/Object/ReferenceEquals/referenceequals4.cs" interactive="try-dotnet-method" id="Snippet1":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ReferenceEquals/referenceequals4.fs" id="Snippet1":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.referenceequals/vb/referenceequals4.vb" id="Snippet1":::
For information on boxing value types, see [Boxing and Unboxing](/dotnet/csharp/programming-guide/types/boxing-and-unboxing).
@@ -977,6 +999,7 @@ and the interface. The method returns `true` if the string is interned. It does not perform a test for value equality. In the following example, `s1` and `s2` are equal because they are two instances of a single interned string. However, `s3` and `s4` are not equal, because although they have identical string values, that string is not interned.
:::code language="csharp" source="~/snippets/csharp/System/Object/ReferenceEquals/referenceequalsa.cs" interactive="try-dotnet-method" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ReferenceEquals/referenceequalsa.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.referenceequals/vb/referenceequalsa.vb" id="Snippet2":::
For more information about string interning, see .
@@ -989,6 +1012,7 @@ and the interface. The
@@ -1061,12 +1085,14 @@ and the interface. The is the base class of all reference types in the .NET Framework, this behavior is inherited by reference types that do not override the method. The following example illustrates this. It defines a class named `Object1` that accepts the default implementation of all members. Its method returns the object's fully qualified type name.
:::code language="cpp" source="~/snippets/cpp/VS_Snippets_CLR_System/system.object.tostring/cpp/tostring2.cpp" id="Snippet2":::
:::code language="csharp" source="~/snippets/csharp/System/Object/ToString/tostring2.cs" interactive="try-dotnet" id="Snippet2":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ToString/tostring2.fs" id="Snippet2":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.tostring/vb/tostring2.vb" id="Snippet2":::
@@ -1075,6 +1101,7 @@ and the interface. The method.
@@ -1096,11 +1123,13 @@ and the interface. The method to display culture-sensitive formatting of a currency value.
:::code language="csharp" source="~/snippets/csharp/System/Object/ToString/tostringoverload2.cs" id="Snippet5":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ToString/tostringoverload2.fs" id="Snippet5":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.tostring/vb/tostringoverload2.vb" id="Snippet5":::
For more information on format strings and culture-sensitive formatting, see [Formatting Types](/dotnet/standard/base-types/formatting-types). For the format strings supported by numeric values, see [Standard Numeric Format Strings](/dotnet/standard/base-types/standard-numeric-format-strings) and [Custom Numeric Format Strings](/dotnet/standard/base-types/custom-numeric-format-strings). For the format strings supported by date and time values, see [Standard Date and Time Format Strings](/dotnet/standard/base-types/standard-date-and-time-format-strings) and [Custom Date and Time Format Strings](/dotnet/standard/base-types/custom-date-and-time-format-strings).
@@ -1110,6 +1139,7 @@ and the interface. The method, you may find its behavior undesirable and want to change it. This is particularly true of arrays and collection classes. While you may expect the `ToString` method of an array or collection class to display the values of its members, it instead displays the type fully qualified type name, as the following example shows.
:::code language="csharp" source="~/snippets/csharp/System/Object/ToString/array1.cs" interactive="try-dotnet-method" id="Snippet6":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ToString/array1.fs" id="Snippet6":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.tostring/vb/array1.vb" id="Snippet6":::
You have several options to produce the result string that you'd like.
@@ -1125,6 +1155,7 @@ and the interface. The class. It overrides the method to display the value of each method of the collection rather than the fully qualified type name.
:::code language="csharp" source="~/snippets/csharp/System/Object/ToString/customize1.cs" interactive="try-dotnet" id="Snippet7":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ToString/customize1.fs" id="Snippet7":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.tostring/vb/customize1.vb" id="Snippet7":::
- Develop an [extension method](/dotnet/standard/design-guidelines/extension-methods) that returns the result string that you want. Note that you can't override the default method in this way (that is, your extension class (in C#) or module (in Visual Basic) cannot have a parameterless method named `ToString` that is called in place of the original type's `ToString` method. You'll have to provide some other name for your parameterless `ToString` replacement.
@@ -1132,6 +1163,7 @@ and the interface. The class: a parameterless `ToString2` method, and a `ToString` method with a parameter that represents a format string.
:::code language="csharp" source="~/snippets/csharp/System/Object/ToString/customize2.cs" interactive="try-dotnet" id="Snippet8":::
+ :::code language="fsharp" source="~/snippets/fsharp/System/Object/ToString/customize2.fs" id="Snippet8":::
:::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.object.tostring/vb/customize2.vb" id="Snippet8":::