From 0e5b2ae3bdc8d868960b03d062990db0bc7e9c52 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 15 May 2018 09:46:09 -0400 Subject: [PATCH 1/4] update tuples project for C# 7.3 New samples have been added for explaining tuple equality. This applies to dotnet/docs#3965 --- snippets/csharp/tuples/tuples/Person.cs | 38 ++++++++++++++++ snippets/csharp/tuples/tuples/Program.cs | 44 ++++++++++++++++++- snippets/csharp/tuples/tuples/packages.config | 2 +- snippets/csharp/tuples/tuples/tuples.csproj | 5 +-- 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/snippets/csharp/tuples/tuples/Person.cs b/snippets/csharp/tuples/tuples/Person.cs index 4cc19d260ec..9c84ad88b94 100644 --- a/snippets/csharp/tuples/tuples/Person.cs +++ b/snippets/csharp/tuples/tuples/Person.cs @@ -48,3 +48,41 @@ public static void Deconstruct(this Student s, out string first, out string last } #endregion } + +namespace TupleEquality +{ + public class Person + { + public string FirstName { get; } + public string LastName { get; } + + public Person(string first, string last) + { + FirstName = first; + LastName = last; + } + + public void Deconstruct(out string firstName, out string lastName) + { + firstName = FirstName; + lastName = LastName; + } + + public static bool operator ==(Person left, Person right) + { + + if (left == null) return (right == null); + if (right == null) return false; // left can't be null here + return (left.FirstName, left.LastName) == (right.FirstName, right.LastName); + } + + public static bool operator !=(Person left, Person right) + { + if (left == null) return (right != null); + if (right == null) return true; // left can't be null here + return (left.FirstName, left.LastName) != (right.FirstName, right.LastName); + } + + } + +} diff --git a/snippets/csharp/tuples/tuples/Program.cs b/snippets/csharp/tuples/tuples/Program.cs index 032d2652cf5..c3b90fb57f3 100644 --- a/snippets/csharp/tuples/tuples/Program.cs +++ b/snippets/csharp/tuples/tuples/Program.cs @@ -43,6 +43,48 @@ static void Main(string[] args) FunWithProjections(); + // Declare different members and tuples: + + + // + var left = (a: 5, b: 10); + var right = (a: 5, b: 10); + Console.WriteLine(left == right); // displays 'true' + // + + // + (int a, int b)? nullableTuple = right; + Console.WriteLine(left == nullableTuple); // Also true + // + + // + // lifted conversions + (int? a, int? b) nullableMembers = (5, 10); + Console.WriteLine(left == nullableMembers); // Also true + + // converted type of left is (long, long) + (long a, long b) longTuple = (5, 10); + Console.WriteLine(left == longTuple); // Also true + + // comparisons performed on (long, long) tuples + (long a, int b) longFirst = (5, 10); + (int a, long b) longSecond = (5, 10); + Console.WriteLine(longFirst == longSecond); // Also true + // + + // + (int a, string b) pair = (1, "Hello"); + (int z, string y) another = (1, "Hello"); + Console.WriteLine(pair == another); // true. Member names don't participate. + Console.WriteLine(pair == (z: 1, y: "Hello")); // warning: literal contains different member names + // + + // + (int, (int, int)) nestedTuple = (1, (2, 3)); + Console.WriteLine(nestedTuple == (1, (2, 3)) ); + // + + // Value based equality tests (Person) } private static void FunWithProjections() @@ -72,7 +114,7 @@ private static void FunWithProjections() Console.WriteLine(projections.Item2); // Accessing the third field: Console.WriteLine(projections.Item3); - // There is no semantic name 'Item`. + // There is no semantic name 'Item1`. var pt1 = (X: 3, Y: 0); var pt2 = (X: 3, Y: 4); diff --git a/snippets/csharp/tuples/tuples/packages.config b/snippets/csharp/tuples/tuples/packages.config index f9c3485db89..dc6e2399a18 100644 --- a/snippets/csharp/tuples/tuples/packages.config +++ b/snippets/csharp/tuples/tuples/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/snippets/csharp/tuples/tuples/tuples.csproj b/snippets/csharp/tuples/tuples/tuples.csproj index d9fff692c6e..7b7a3dcf89d 100644 --- a/snippets/csharp/tuples/tuples/tuples.csproj +++ b/snippets/csharp/tuples/tuples/tuples.csproj @@ -35,9 +35,8 @@ - - ..\packages\System.ValueTuple.4.3.0-preview1-24530-04\lib\netstandard1.0\System.ValueTuple.dll - True + + ..\packages\System.ValueTuple.4.5.0-rc1\lib\netstandard1.0\System.ValueTuple.dll From b86bfac4bc712bf1f189651b383a4aa5a2fba692 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 15 May 2018 10:37:29 -0400 Subject: [PATCH 2/4] finish the equality tests samples --- snippets/csharp/tuples/tuples/Person.cs | 59 +++++++++++++++++++----- snippets/csharp/tuples/tuples/Program.cs | 23 ++++++++- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/snippets/csharp/tuples/tuples/Person.cs b/snippets/csharp/tuples/tuples/Person.cs index 9c84ad88b94..a3bc797c32d 100644 --- a/snippets/csharp/tuples/tuples/Person.cs +++ b/snippets/csharp/tuples/tuples/Person.cs @@ -51,6 +51,41 @@ public static void Deconstruct(this Student s, out string first, out string last namespace TupleEquality { + public static class Tests + { + public static void EqualityTests() + { + Person nil = default; + Person blank = new Person(null, null); + Person sample = new Person("Bill", "Wagner"); + + Console.WriteLine("Starting Equality Tests"); + Console.WriteLine($"nill equals nil: {nil == nil}"); + Console.WriteLine($"nill equals blank: {nil == blank}"); + Console.WriteLine($"nill equals sample: {nil == sample}"); + + Console.WriteLine($"blank equals nil: {blank == nil}"); + Console.WriteLine($"blank equals blank: {blank == blank}"); + Console.WriteLine($"blank equals sanple: {blank == sample}"); + + Console.WriteLine($"sample equals nil: {sample == nil}"); + Console.WriteLine($"sample equals blank: {sample == blank}"); + Console.WriteLine($"sample equals sanple: {sample == sample}"); + + Console.WriteLine($"nill not equals nil: {nil != nil}"); + Console.WriteLine($"nill not equals blank: {nil != blank}"); + Console.WriteLine($"nill not equals sample: {nil != sample}"); + + Console.WriteLine($"blank not equals nil: {blank != nil}"); + Console.WriteLine($"blank not equals blank: {blank != blank}"); + Console.WriteLine($"blank not equals sanple: {blank != sample}"); + + Console.WriteLine($"sample not equals nil: {sample != nil}"); + Console.WriteLine($"sample not equals blank: {sample != blank}"); + Console.WriteLine($"sample not equals sanple: {sample != sample}"); + + } + } public class Person { public string FirstName { get; } @@ -68,20 +103,20 @@ public void Deconstruct(out string firstName, out string lastName) lastName = LastName; } - public static bool operator ==(Person left, Person right) - { + // + public override bool Equals(object other) => + (other is Person p) + ? (FirstName, LastName) == (p.FirstName, p.LastName) + : false; - if (left == null) return (right == null); - if (right == null) return false; // left can't be null here - return (left.FirstName, left.LastName) == (right.FirstName, right.LastName); - } + public static bool operator ==(Person left, Person right) => + (object.ReferenceEquals(left, null)) + ? (object.ReferenceEquals(right, null)) + : left.Equals(right); - public static bool operator !=(Person left, Person right) - { - if (left == null) return (right != null); - if (right == null) return true; // left can't be null here - return (left.FirstName, left.LastName) != (right.FirstName, right.LastName); - } + public static bool operator !=(Person left, Person right) => !(left == right); + public override int GetHashCode() => $"{LastName}{FirstName}".GetHashCode(); + // } diff --git a/snippets/csharp/tuples/tuples/Program.cs b/snippets/csharp/tuples/tuples/Program.cs index c3b90fb57f3..c9ad28d5f6b 100644 --- a/snippets/csharp/tuples/tuples/Program.cs +++ b/snippets/csharp/tuples/tuples/Program.cs @@ -14,7 +14,7 @@ static void Main(string[] args) AssignmentStatements(); - var sample = new List{ 2.0, 4.0, 6.0, 8.0 }; + var sample = new List { 2.0, 4.0, 6.0, 8.0 }; Console.WriteLine(StatisticsVersionOne.StandardDeviation(sample)); @@ -45,20 +45,38 @@ static void Main(string[] args) // Declare different members and tuples: + SimpleTupleEquality(); + NullableTupleEquality(); + MemberConversions(); + MemberNameConversions(); + TupleEquality.Tests.EqualityTests(); + } + + private static void SimpleTupleEquality() + { // var left = (a: 5, b: 10); var right = (a: 5, b: 10); Console.WriteLine(left == right); // displays 'true' // + } + private static void NullableTupleEquality() + { // + var left = (a: 5, b: 10); + var right = (a: 5, b: 10); (int a, int b)? nullableTuple = right; Console.WriteLine(left == nullableTuple); // Also true // + } + private static void MemberConversions() + { // // lifted conversions + var left = (a: 5, b: 10); (int? a, int? b) nullableMembers = (5, 10); Console.WriteLine(left == nullableMembers); // Also true @@ -71,7 +89,10 @@ static void Main(string[] args) (int a, long b) longSecond = (5, 10); Console.WriteLine(longFirst == longSecond); // Also true // + } + private static void MemberNameConversions() + { // (int a, string b) pair = (1, "Hello"); (int z, string y) another = (1, "Hello"); From bbd133c834042083fb9f5a125607c53b365170a5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 15 May 2018 10:57:43 -0400 Subject: [PATCH 3/4] GetHashCode should use tuples too. --- snippets/csharp/tuples/tuples/Person.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snippets/csharp/tuples/tuples/Person.cs b/snippets/csharp/tuples/tuples/Person.cs index a3bc797c32d..57201a2669d 100644 --- a/snippets/csharp/tuples/tuples/Person.cs +++ b/snippets/csharp/tuples/tuples/Person.cs @@ -115,7 +115,7 @@ public override bool Equals(object other) => : left.Equals(right); public static bool operator !=(Person left, Person right) => !(left == right); - public override int GetHashCode() => $"{LastName}{FirstName}".GetHashCode(); + public override int GetHashCode() => (LastName, FirstName).GetHashCode(); // } From f0fbaee93d1e6181dcb293f07624a770df70891b Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 15 May 2018 12:11:09 -0400 Subject: [PATCH 4/4] respond to feedback. --- snippets/csharp/tuples/tuples/Person.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/snippets/csharp/tuples/tuples/Person.cs b/snippets/csharp/tuples/tuples/Person.cs index 57201a2669d..7655e72ecff 100644 --- a/snippets/csharp/tuples/tuples/Person.cs +++ b/snippets/csharp/tuples/tuples/Person.cs @@ -60,9 +60,9 @@ public static void EqualityTests() Person sample = new Person("Bill", "Wagner"); Console.WriteLine("Starting Equality Tests"); - Console.WriteLine($"nill equals nil: {nil == nil}"); - Console.WriteLine($"nill equals blank: {nil == blank}"); - Console.WriteLine($"nill equals sample: {nil == sample}"); + Console.WriteLine($"nil equals nil: {nil == nil}"); + Console.WriteLine($"nil equals blank: {nil == blank}"); + Console.WriteLine($"nil equals sample: {nil == sample}"); Console.WriteLine($"blank equals nil: {blank == nil}"); Console.WriteLine($"blank equals blank: {blank == blank}"); @@ -72,9 +72,9 @@ public static void EqualityTests() Console.WriteLine($"sample equals blank: {sample == blank}"); Console.WriteLine($"sample equals sanple: {sample == sample}"); - Console.WriteLine($"nill not equals nil: {nil != nil}"); - Console.WriteLine($"nill not equals blank: {nil != blank}"); - Console.WriteLine($"nill not equals sample: {nil != sample}"); + Console.WriteLine($"nil not equals nil: {nil != nil}"); + Console.WriteLine($"nil not equals blank: {nil != blank}"); + Console.WriteLine($"nil not equals sample: {nil != sample}"); Console.WriteLine($"blank not equals nil: {blank != nil}"); Console.WriteLine($"blank not equals blank: {blank != blank}");