From 343ffa6ec366ab0725126bc88edeaf7a790c8870 Mon Sep 17 00:00:00 2001 From: albert-du <52804499+albert-du@users.noreply.github.com> Date: Fri, 25 Feb 2022 20:00:13 -0800 Subject: [PATCH] IEquatable F# snippets --- .../System/IEquatableT/Equals/EqualsEx2.fs | 93 +++++++++++++++++++ .../System/IEquatableT/Equals/Snippet12.fs | 80 ++++++++++++++++ .../System/IEquatableT/Equals/fs.fsproj | 11 +++ xml/System/IEquatable`1.xml | 2 + 4 files changed, 186 insertions(+) create mode 100644 snippets/fsharp/System/IEquatableT/Equals/EqualsEx2.fs create mode 100644 snippets/fsharp/System/IEquatableT/Equals/Snippet12.fs create mode 100644 snippets/fsharp/System/IEquatableT/Equals/fs.fsproj diff --git a/snippets/fsharp/System/IEquatableT/Equals/EqualsEx2.fs b/snippets/fsharp/System/IEquatableT/Equals/EqualsEx2.fs new file mode 100644 index 00000000000..29e42d75a6a --- /dev/null +++ b/snippets/fsharp/System/IEquatableT/Equals/EqualsEx2.fs @@ -0,0 +1,93 @@ +module EqualsEx2 + +// +open System +open System.Text.RegularExpressions + +type Person(lastName, ssn) = + let mutable lastName = lastName + let ssn = + if Regex.IsMatch(ssn, @"\d{9}") then + $"{ssn.Substring(0, 3)}-{ssn.Substring(3, 2)}-{ssn.Substring(5, 4)}" + elif Regex.IsMatch(ssn, @"\d{3}-\d{2}-\d{4}") then + ssn + else + raise (FormatException "The social security number has an invalid format.") + + member _.SSN = + ssn + + member _.LastName + with get () = lastName + and set (value) = + if String.IsNullOrEmpty value then + invalidArg (nameof value) "The last name cannot be null or empty." + else + lastName <- value + + static member op_Equality (person1: Person, person2: Person) = + if box person1 |> isNull || box person2 |> isNull then + Object.Equals(person1, person2) + else + person1.Equals person2 + + static member op_Inequality (person1: Person, person2: Person) = + if box person1 |> isNull || box person2 |> isNull then + Object.Equals(person1, person2) |> not + else + person1.Equals person2 |> not + + override _.GetHashCode() = + ssn.GetHashCode() + + override this.Equals(obj: obj) = + match obj with + | :? Person as personObj -> + (this :> IEquatable<_>).Equals personObj + | _ -> false + + interface IEquatable with + member this.Equals(other: Person) = + match box other with + | null -> false + | _ -> + this.SSN = other.SSN +// +// Create a Person object for each job applicant. +let applicant1 = Person("Jones", "099-29-4999") +let applicant2 = Person("Jones", "199-29-3999") +let applicant3 = Person("Jones", "299-49-6999") + +// Add applicants to a List object. +let applicants = ResizeArray() +applicants.Add applicant1 +applicants.Add applicant2 +applicants.Add applicant3 + +// Create a Person object for the final candidate. +let candidate = Person("Jones", "199-29-3999") +if applicants.Contains candidate then + printfn $"Found {candidate.LastName} (SSN {candidate.SSN})." +else + printfn $"Applicant {candidate.SSN} not found." + +// Call the shared inherited Equals(Object, Object) method. +// It will in turn call the IEquatable.Equals implementation. +printfn $"{applicant2.LastName}({applicant2.SSN}) already on file: {Person.Equals(applicant2, candidate)}." + +// The example displays the following output: +// Found Jones (SSN 199-29-3999). +// Jones(199-29-3999) already on file: True. + +// This tests the handling of null values, but does not appear in the documentation. +// +//public class Example +//{ +// public static void Main() +// { +// var p1 = new Person("Joe", "613-24-0068") +// Person p2 = null +// +// Console.WriteLine(p1 == p2) +// } +//} \ No newline at end of file diff --git a/snippets/fsharp/System/IEquatableT/Equals/Snippet12.fs b/snippets/fsharp/System/IEquatableT/Equals/Snippet12.fs new file mode 100644 index 00000000000..39e48b695c9 --- /dev/null +++ b/snippets/fsharp/System/IEquatableT/Equals/Snippet12.fs @@ -0,0 +1,80 @@ +open System +open System.Collections.Generic +open System.Text.RegularExpressions + +type Person(lastName, ssn) = + let mutable lastName = lastName + let ssn = + if Regex.IsMatch(ssn, @"\d{9}") then + $"{ssn.Substring(0, 3)}-{ssn.Substring(3, 2)}-{ssn.Substring(5, 4)}" + elif Regex.IsMatch(ssn, @"\d{3}-\d{2}-\d{4}") then + ssn + else + raise (FormatException "The social security number has an invalid format.") + + member _.SSN = + ssn + + member _.LastName + with get () = lastName + and set (value) = + if String.IsNullOrEmpty value then + invalidArg (nameof value) "The last name cannot be null or empty." + else + lastName <- value + + static member op_Equality (person1: Person, person2: Person) = + if box person1 |> isNull || box person2 |> isNull then + Object.Equals(person1, person2) + else + person1.Equals person2 + + static member op_Inequality (person1: Person, person2: Person) = + if box person1 |> isNull || box person2 |> isNull then + Object.Equals(person1, person2) |> not + else + person1.Equals person2 |> not + + override _.GetHashCode() = + ssn.GetHashCode() + + override this.Equals(obj: obj) = + match obj with + | :? Person as personObj -> + (this :> IEquatable<_>).Equals personObj + | _ -> false + + interface IEquatable with + member this.Equals(other: Person) = + match box other with + | null -> false + | _ -> + this.SSN = other.SSN + +// +// Create a Person object for each job applicant. +let applicant1 = Person("Jones", "099-29-4999") +let applicant2 = Person("Jones", "199-29-3999") +let applicant3 = Person("Jones", "299-49-6999") + +// Add applicants to a List object. +let applicants = ResizeArray() +applicants.Add applicant1 +applicants.Add applicant2 +applicants.Add applicant3 + +// Create a Person object for the final candidate. +let candidate = Person("Jones", "199-29-3999") +if applicants.Contains candidate then + printfn $"Found {candidate.LastName} (SSN {candidate.SSN})." +else + printfn $"Applicant {candidate.SSN} not found." + +// Call the shared inherited Equals(Object, Object) method. +// It will in turn call the IEquatable.Equals implementation. +printfn $"{applicant2.LastName}({applicant2.SSN}) already on file: {Person.Equals(applicant2, candidate)}." + +// The example displays the following output: +// Found Jones (SSN 199-29-3999). +// Jones(199-29-3999) already on file: True. +// \ No newline at end of file diff --git a/snippets/fsharp/System/IEquatableT/Equals/fs.fsproj b/snippets/fsharp/System/IEquatableT/Equals/fs.fsproj new file mode 100644 index 00000000000..34dea6b9fa0 --- /dev/null +++ b/snippets/fsharp/System/IEquatableT/Equals/fs.fsproj @@ -0,0 +1,11 @@ + + + Exe + net6.0 + + + + + + + \ No newline at end of file diff --git a/xml/System/IEquatable`1.xml b/xml/System/IEquatable`1.xml index a7756ea197f..7ded37fb1a2 100644 --- a/xml/System/IEquatable`1.xml +++ b/xml/System/IEquatable`1.xml @@ -145,11 +145,13 @@ The following example shows the partial implementation of a `Person` class that implements and has two properties, `LastName` and `SSN`. The method returns `True` if the `SSN` property of two `Person` objects is identical; otherwise, it returns `False`. :::code language="csharp" source="~/snippets/csharp/System/IEquatableT/Equals/EqualsEx2.cs" id="Snippet3"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IEquatableT/Equals/EqualsEx2.fs" id="Snippet3"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.GenericIEquatable.Equals/vb/EqualsEx2.vb" id="Snippet3"::: `Person` objects can then be stored in a object and can be identified by the `Contains` method, as the following example shows. :::code language="csharp" source="~/snippets/csharp/System/IEquatableT/Equals/Snippet12.cs" id="Snippet12"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IEquatableT/Equals/Snippet12.fs" id="Snippet12"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.GenericIEquatable.Equals/vb/Snippet12.vb" id="Snippet12"::: ]]>