Implement IEquatable<T> on value types overriding Equals (and enable CA1066/1077...
authorStephen Toub <stoub@microsoft.com>
Mon, 24 Jan 2022 14:43:25 +0000 (09:43 -0500)
committerGitHub <noreply@github.com>
Mon, 24 Jan 2022 14:43:25 +0000 (09:43 -0500)
111 files changed:
eng/CodeAnalysis.src.globalconfig
src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs [deleted file]
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs [deleted file]
src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/ModuleHandle.cs
src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs
src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs
src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs
src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs
src/coreclr/tools/Common/TypeSystem/Common/LayoutInt.cs
src/libraries/Common/src/Interop/Unix/System.Native/Interop.IPAddress.cs
src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs
src/libraries/Microsoft.Extensions.Logging.Abstractions/ref/Microsoft.Extensions.Logging.Abstractions.cs
src/libraries/Microsoft.Extensions.Logging.Abstractions/src/EventId.cs
src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.HashBucket.cs
src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.HashBucket.cs
src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs
src/libraries/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs
src/libraries/System.Collections.Specialized/tests/BitVector32Tests.cs
src/libraries/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs
src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs
src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs
src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/InterlockedBitVector32.cs
src/libraries/System.Data.Common/ref/System.Data.Common.cs
src/libraries/System.Data.Common/src/System/Data/DataKey.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBinary.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBoolean.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLByte.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDouble.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLGuid.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt16.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt32.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt64.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLMoney.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLSingle.cs
src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLString.cs
src/libraries/System.Data.Common/src/System/Data/Selection.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBinaryTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBooleanTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlByteTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDateTimeTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDecimalTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDoubleTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlGuidTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt16Test.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt64Test.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlMoneyTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlSingleTest.cs
src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringTest.cs
src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj
src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs [new file with mode: 0644]
src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj
src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/CounterSample.cs
src/libraries/System.Diagnostics.StackTrace/ref/System.Diagnostics.StackTrace.cs
src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/SymbolStore/SymbolToken.cs
src/libraries/System.Drawing.Common/ref/System.Drawing.Common.netcoreapp.cs
src/libraries/System.Drawing.Common/src/System/Drawing/CharacterRange.cs
src/libraries/System.Drawing.Common/src/System/Drawing/Printing/TriState.cs
src/libraries/System.Drawing.Common/tests/CharacterRangeTests.cs
src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalVariables.cs
src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/IPPacketInformation.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs
src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventDescriptor.cs
src/libraries/System.Private.CoreLib/src/System/HashCode.cs
src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
src/libraries/System.Private.CoreLib/src/System/Nullable.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeNamedArgument.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeTypedArgument.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/Serialization/StreamingContext.cs
src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs
src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.ThreadCounts.cs
src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerTracking.cs
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs
src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs
src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/Pair.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryCardinality.cs
src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs
src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheUsage.cs
src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/GCHandleTests.cs
src/libraries/System.Runtime/ref/System.Runtime.cs
src/libraries/System.Runtime/tests/System/Reflection/CustomAttribute_Named_Typed_ArgumentTests.cs
src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs
src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj
src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeDescription.cs
src/libraries/System.Speech/src/Internal/Synthesis/EngineSiteSapi.cs
src/libraries/System.Text.Encodings.Web/src/Polyfills/System.Text.Rune.netstandard20.cs
src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicMatch.cs
src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexInfo.cs
src/libraries/System.Threading/ref/System.Threading.cs
src/libraries/System.Threading/src/System/Threading/LockCookie.cs
src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs
src/mono/System.Private.CoreLib/src/Mono/RuntimeHandles.cs
src/mono/System.Private.CoreLib/src/System/ModuleHandle.cs
src/mono/System.Private.CoreLib/src/System/Nullable.Mono.cs
src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs
src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs

index 0fc9bf8..e5ae419 100644 (file)
@@ -152,10 +152,10 @@ dotnet_diagnostic.CA1064.severity = none
 dotnet_diagnostic.CA1065.severity = none
 
 # CA1066: Implement IEquatable when overriding Object.Equals
-dotnet_diagnostic.CA1066.severity = none
+dotnet_diagnostic.CA1066.severity = warning
 
 # CA1067: Override Object.Equals(object) when implementing IEquatable<T>
-dotnet_diagnostic.CA1067.severity = none
+dotnet_diagnostic.CA1067.severity = warning
 
 # CA1068: CancellationToken parameters must come last
 dotnet_diagnostic.CA1068.severity = none
index e1230d5..3d21bff 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrame.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrameHelper.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackTrace.CoreCLR.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Diagnostics\SymbolStore\SymAddressKind.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Diagnostics\SymbolStore\Token.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Enum.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Environment.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Exception.CoreCLR.cs" />
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs
deleted file mode 100644 (file)
index dc2a0a0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*============================================================
-**
-**
-**
-** Represents address Kinds used with local variables, parameters, and
-** fields.
-**
-**
-===========================================================*/
-// Only statics, does not need to be marked with the serializable attribute
-
-namespace System.Diagnostics.SymbolStore
-{
-    internal enum SymAddressKind
-    {
-        // ILOffset: addr1 = IL local var or param index.
-        ILOffset = 1,
-
-        // NativeRVA: addr1 = RVA into module.
-        NativeRVA = 2,
-
-        // NativeRegister: addr1 = register the var is stored in.
-        NativeRegister = 3,
-
-        // NativeRegisterRelative: addr1 = register, addr2 = offset.
-        NativeRegisterRelative = 4,
-
-        // NativeOffset: addr1 = offset from start of parent.
-        NativeOffset = 5,
-
-        // NativeRegisterRegister: addr1 = reg low, addr2 = reg high.
-        NativeRegisterRegister = 6,
-
-        // NativeRegisterStack: addr1 = reg low, addr2 = reg stk, addr3 = offset.
-        NativeRegisterStack = 7,
-
-        // NativeStackRegister: addr1 = reg stk, addr2 = offset, addr3 = reg high.
-        NativeStackRegister = 8,
-
-        // BitField: addr1 = field start, addr = field length.
-        BitField = 9,
-
-        // NativeSectionOffset: addr1 = section, addr = offset
-        NativeSectionOffset = 10,
-    }
-}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs
deleted file mode 100644 (file)
index fbd9f7e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/*============================================================
-**
-**
-** Small value class used by the SymbolStore package for passing
-** around metadata tokens.
-**
-===========================================================*/
-
-using System.Diagnostics.CodeAnalysis;
-
-namespace System.Diagnostics.SymbolStore
-{
-    internal struct SymbolToken
-    {
-        internal int m_token;
-
-        public SymbolToken(int val) { m_token = val; }
-
-        public int GetToken() { return m_token; }
-
-        public override int GetHashCode() { return m_token; }
-
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            if (obj is SymbolToken)
-                return Equals((SymbolToken)obj);
-            else
-                return false;
-        }
-
-        public bool Equals(SymbolToken obj)
-        {
-            return obj.m_token == m_token;
-        }
-    }
-}
index 9368fc2..cdc15dc 100644 (file)
@@ -194,7 +194,9 @@ namespace System.Reflection
         }
     }
 
+#pragma warning disable CA1066 // IEquatable<MetadataImport> interface implementation isn't used
     internal readonly struct MetadataImport
+#pragma warning restore CA1067
     {
         private readonly IntPtr m_metadataImport2;
         private readonly object? m_keepalive;
index 977d73e..32a37b6 100644 (file)
@@ -1246,7 +1246,7 @@ namespace System
         }
     }
 
-    public unsafe partial struct ModuleHandle
+    public unsafe partial struct ModuleHandle : IEquatable<ModuleHandle>
     {
         #region Public Static Members
         public static readonly ModuleHandle EmptyHandle;
index 3714e7c..d1bb831 100644 (file)
@@ -6,7 +6,7 @@ using System.Reflection;
 
 namespace System
 {
-    public struct ModuleHandle
+    public struct ModuleHandle : IEquatable<ModuleHandle>
     {
         public static readonly ModuleHandle EmptyHandle;
 
index b44cf57..fe06816 100644 (file)
@@ -34,6 +34,8 @@ using Internal.Reflection.Core.Execution;
 //   - The TypeUnifier extension class provides a more friendly interface to the rest of the codebase.
 //
 
+#pragma warning disable CA1067 // override Equals because it implements IEquatable<T>
+
 namespace System.Reflection.Runtime.General
 {
     internal static partial class TypeUnifier
index 55b09b3..aa1a796 100644 (file)
@@ -20,6 +20,7 @@ class ReaderGen : CsWriter
         WriteLine("#pragma warning disable 649");
         WriteLine("#pragma warning disable 169");
         WriteLine("#pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct");
+        WriteLine("#pragma warning disable CA1066 // IEquatable<T> implementations aren't used");
         WriteLine("#pragma warning disable IDE0059");
         WriteLine();
 
index 1d92be5..bbc23ec 100644 (file)
@@ -6,6 +6,7 @@
 #pragma warning disable 649
 #pragma warning disable 169
 #pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct
+#pragma warning disable CA1066 // IEquatable<T> implementations aren't used
 #pragma warning disable IDE0059
 
 using System;
index 8eba905..5b7921f 100644 (file)
@@ -1,12 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-
 #pragma warning disable 169
-
-// There is no defined ordering between fields in multiple declarations of partial class or struct
-#pragma warning disable 282
-
+#pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct
+#pragma warning disable CA1066 // IEquatable<T> implementations aren't used
 
 using System;
 using System.IO;
index 2ec3883..c794377 100644 (file)
@@ -12,7 +12,9 @@ namespace Internal.TypeSystem
     /// type system do not have a known size. This type is used to make such sizes viral through the type layout
     /// computations)
     /// </summary>
+#pragma warning disable CA1066 // IEquatable<T> implementation wouldn't be used
     public struct LayoutInt
+#pragma warning restore CA1066
     {
         private int _value;
 
index 567f97d..4bbd799 100644 (file)
@@ -2,9 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
-using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Runtime.InteropServices;
-using System.Text;
 
 internal static partial class Interop
 {
@@ -33,6 +32,19 @@ internal static partial class Interop
             private  uint _isIPv6;                             // Non-zero if this is an IPv6 address; zero for IPv4.
             internal uint ScopeId;                             // Scope ID (IPv6 only)
 
+            public override unsafe int GetHashCode()
+            {
+                HashCode h = default;
+                fixed (byte* ptr = Address)
+                {
+                    h.AddBytes(new ReadOnlySpan<byte>(ptr, IsIPv6 ? IPv6AddressBytes : IPv4AddressBytes));
+                }
+                return h.ToHashCode();
+            }
+
+            public override bool Equals([NotNullWhen(true)] object? obj) =>
+                obj is IPAddress other && Equals(other);
+
             public bool Equals(IPAddress other)
             {
                 int addressByteCount;
index 8f812ae..737c23d 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
+using System.Diagnostics.CodeAnalysis;
 
 namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
 {
@@ -33,10 +34,14 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
             Slot = slot;
         }
 
-        public bool Equals(ServiceCacheKey other)
-        {
-            return Type == other.Type && Slot == other.Slot;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(ServiceCacheKey other) =>
+            Type == other.Type && Slot == other.Slot;
+
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is ServiceCacheKey other && Equals(other);
 
         public override int GetHashCode()
         {
index 1404880..33e79ca 100644 (file)
@@ -6,7 +6,7 @@
 
 namespace Microsoft.Extensions.Logging
 {
-    public readonly partial struct EventId
+    public readonly partial struct EventId : System.IEquatable<Microsoft.Extensions.Logging.EventId>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
index 972fb1e..1cb4775 100644 (file)
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Diagnostics.CodeAnalysis;
 
 namespace Microsoft.Extensions.Logging
@@ -8,7 +9,7 @@ namespace Microsoft.Extensions.Logging
     /// <summary>
     /// Identifies a logging event. The primary identifier is the "Id" property, with the "Name" property providing a short description of this type of event.
     /// </summary>
-    public readonly struct EventId
+    public readonly struct EventId : IEquatable<EventId>
     {
         /// <summary>
         /// Implicitly creates an EventId from the given <see cref="int"/>.
index aa8d763..2562372 100644 (file)
@@ -15,7 +15,9 @@ namespace System.Collections.Immutable
         /// <summary>
         /// Contains all the key/values in the collection that hash to the same value.
         /// </summary>
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
         internal readonly struct HashBucket : IEnumerable<KeyValuePair<TKey, TValue>>
+#pragma warning restore CA1066
         {
             /// <summary>
             /// One of the values in this bucket.
index 82fd48f..04ca794 100644 (file)
@@ -30,7 +30,9 @@ namespace System.Collections.Immutable
         /// <summary>
         /// Contains all the keys in the collection that hash to the same value.
         /// </summary>
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
         internal readonly struct HashBucket
+#pragma warning restore CA1066
         {
             /// <summary>
             /// One of the values in this bucket.
index 1864717..00fc77e 100644 (file)
@@ -6,7 +6,7 @@
 
 namespace System.Collections.Specialized
 {
-    public partial struct BitVector32
+    public partial struct BitVector32 : System.IEquatable<System.Collections.Specialized.BitVector32>
     {
         private int _dummyPrimitive;
         public BitVector32(System.Collections.Specialized.BitVector32 value) { throw null; }
@@ -18,11 +18,12 @@ namespace System.Collections.Specialized
         public static int CreateMask(int previous) { throw null; }
         public static System.Collections.Specialized.BitVector32.Section CreateSection(short maxValue) { throw null; }
         public static System.Collections.Specialized.BitVector32.Section CreateSection(short maxValue, System.Collections.Specialized.BitVector32.Section previous) { throw null; }
+        public bool Equals(System.Collections.Specialized.BitVector32 other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; }
         public override int GetHashCode() { throw null; }
         public override string ToString() { throw null; }
         public static string ToString(System.Collections.Specialized.BitVector32 value) { throw null; }
-        public readonly partial struct Section
+        public readonly partial struct Section : System.IEquatable<System.Collections.Specialized.BitVector32.Section>
         {
             private readonly int _dummyPrimitive;
             public short Mask { get { throw null; } }
index ce4ba76..60a2580 100644 (file)
@@ -10,7 +10,7 @@ namespace System.Collections.Specialized
     ///    <para>Provides a simple light bit vector with easy integer or Boolean access to
     ///       a 32 bit storage.</para>
     /// </devdoc>
-    public struct BitVector32
+    public struct BitVector32 : IEquatable<BitVector32>
     {
         private uint _data;
 
@@ -151,7 +151,12 @@ namespace System.Collections.Specialized
             return new Section(mask, offset);
         }
 
-        public override bool Equals([NotNullWhen(true)] object? o) => o is BitVector32 other && _data == other._data;
+        public override bool Equals([NotNullWhen(true)] object? o) => o is BitVector32 other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(BitVector32 other) => _data == other._data;
 
         public override int GetHashCode() => _data.GetHashCode();
 
@@ -182,7 +187,7 @@ namespace System.Collections.Specialized
         ///    <para>
         ///       Represents an section of the vector that can contain a integer number.</para>
         /// </devdoc>
-        public readonly struct Section
+        public readonly struct Section : IEquatable<Section>
         {
             private readonly short _mask;
             private readonly short _offset;
index 61734a0..69453b6 100644 (file)
@@ -518,17 +518,32 @@ namespace System.Collections.Specialized.Tests
             Assert.True(new BitVector32(0).Equals(original));
             Assert.True(original.Equals(new BitVector32(0)));
 
+            Assert.True(original.Equals((object)original));
+            Assert.True(new BitVector32().Equals((object)original));
+            Assert.True(original.Equals((object)new BitVector32()));
+            Assert.True(new BitVector32(0).Equals((object)original));
+            Assert.True(original.Equals((object)new BitVector32(0)));
+
             BitVector32 other = new BitVector32(int.MaxValue / 2 - 1);
             Assert.True(other.Equals(other));
             Assert.True(new BitVector32(int.MaxValue / 2 - 1).Equals(other));
             Assert.True(other.Equals(new BitVector32(int.MaxValue / 2 - 1)));
 
+            Assert.True(other.Equals((object)other));
+            Assert.True(new BitVector32(int.MaxValue / 2 - 1).Equals((object)other));
+            Assert.True(other.Equals((object)new BitVector32(int.MaxValue / 2 - 1)));
+
             Assert.False(other.Equals(original));
             Assert.False(original.Equals(other));
             Assert.False(other.Equals(null));
             Assert.False(original.Equals(null));
             Assert.False(other.Equals(int.MaxValue / 2 - 1));
             Assert.False(original.Equals(0));
+
+            Assert.False(other.Equals((object)original));
+            Assert.False(original.Equals((object)other));
+            Assert.False(other.Equals(int.MaxValue / 2 - 1));
+            Assert.False(original.Equals(0));
         }
 
         [Fact]
index f55f6b2..60accae 100644 (file)
@@ -608,7 +608,7 @@ namespace System.ComponentModel.Composition.Primitives
 }
 namespace System.ComponentModel.Composition.ReflectionModel
 {
-    public partial struct LazyMemberInfo
+    public partial struct LazyMemberInfo : System.IEquatable<System.ComponentModel.Composition.ReflectionModel.LazyMemberInfo>
     {
         private object _dummy;
         private int _dummyPrimitive;
@@ -616,6 +616,7 @@ namespace System.ComponentModel.Composition.ReflectionModel
         public LazyMemberInfo(System.Reflection.MemberTypes memberType, System.Func<System.Reflection.MemberInfo[]> accessorsCreator) { throw null; }
         public LazyMemberInfo(System.Reflection.MemberTypes memberType, params System.Reflection.MemberInfo[] accessors) { throw null; }
         public System.Reflection.MemberTypes MemberType { get { throw null; } }
+        public bool Equals(System.ComponentModel.Composition.ReflectionModel.LazyMemberInfo other) { throw null; }
         public override bool Equals(object? obj) { throw null; }
         public System.Reflection.MemberInfo[] GetAccessors() { throw null; }
         public override int GetHashCode() { throw null; }
index 480e339..02d1f81 100644 (file)
@@ -8,7 +8,7 @@ using Microsoft.Internal;
 
 namespace System.ComponentModel.Composition.ReflectionModel
 {
-    public struct LazyMemberInfo
+    public struct LazyMemberInfo : IEquatable<LazyMemberInfo>
     {
         private readonly MemberTypes _memberType;
         private MemberInfo?[]? _accessors;
@@ -106,31 +106,32 @@ namespace System.ComponentModel.Composition.ReflectionModel
             throw new Exception(SR.Diagnostic_InternalExceptionMessage);
         }
 
-        public override bool Equals(object? obj)
-        {
-            if (obj is not LazyMemberInfo that)
-            {
-                return false;
-            }
+        public override bool Equals(object? obj) =>
+            obj is LazyMemberInfo other && Equals(other);
 
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(LazyMemberInfo other)
+        {
             // Different member types mean different members
-            if (_memberType != that._memberType)
+            if (_memberType != other._memberType)
             {
                 return false;
             }
 
             // if any of the lazy memebers create accessors in a delay-loaded fashion, we simply compare the creators
-            if ((_accessorsCreator != null) || (that._accessorsCreator != null))
+            if ((_accessorsCreator != null) || (other._accessorsCreator != null))
             {
-                return object.Equals(_accessorsCreator, that._accessorsCreator);
+                return object.Equals(_accessorsCreator, other._accessorsCreator);
             }
 
             // we are dealing with explicitly passed accessors in both cases
-            if (_accessors == null || that._accessors == null)
+            if (_accessors == null || other._accessors == null)
             {
                 throw new Exception(SR.Diagnostic_InternalExceptionMessage);
             }
-            return _accessors.SequenceEqual(that._accessors);
+            return _accessors.SequenceEqual(other._accessors);
         }
 
         public static bool operator ==(LazyMemberInfo left, LazyMemberInfo right)
index 510fffc..8fe3c9a 100644 (file)
@@ -2164,7 +2164,7 @@ namespace System.ComponentModel.Design.Serialization
         public object? Invoke() { throw null; }
     }
     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
-    public readonly partial struct MemberRelationship
+    public readonly partial struct MemberRelationship : System.IEquatable<System.ComponentModel.Design.Serialization.MemberRelationship>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
@@ -2173,6 +2173,7 @@ namespace System.ComponentModel.Design.Serialization
         public bool IsEmpty { get { throw null; } }
         public System.ComponentModel.MemberDescriptor Member { get { throw null; } }
         public object? Owner { get { throw null; } }
+        public bool Equals(System.ComponentModel.Design.Serialization.MemberRelationship other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.ComponentModel.Design.Serialization.MemberRelationship left, System.ComponentModel.Design.Serialization.MemberRelationship right) { throw null; }
index 6691792..090fa91 100644 (file)
@@ -153,7 +153,7 @@ namespace System.ComponentModel.Design.Serialization
         /// <summary>
         /// Used as storage in our relationship table
         /// </summary>
-        private struct RelationshipEntry
+        private struct RelationshipEntry : IEquatable<RelationshipEntry>
         {
             internal WeakReference _owner;
             internal MemberDescriptor _member;
@@ -169,20 +169,19 @@ namespace System.ComponentModel.Design.Serialization
             public override bool Equals([NotNullWhen(true)] object? o)
             {
                 Debug.Assert(o is RelationshipEntry, "This is only called indirectly from a dictionary only containing RelationshipEntry structs.");
-                return this == (RelationshipEntry)o;
+                return Equals((RelationshipEntry)o);
             }
 
-            public static bool operator ==(RelationshipEntry re1, RelationshipEntry re2)
+            public bool Equals(RelationshipEntry other)
             {
-                object? owner1 = (re1._owner.IsAlive ? re1._owner.Target : null);
-                object? owner2 = (re2._owner.IsAlive ? re2._owner.Target : null);
-                return owner1 == owner2 && re1._member.Equals(re2._member);
+                object? owner1 = (_owner.IsAlive ? _owner.Target : null);
+                object? owner2 = (other._owner.IsAlive ? other._owner.Target : null);
+                return owner1 == owner2 && _member.Equals(other._member);
             }
 
-            public static bool operator !=(RelationshipEntry re1, RelationshipEntry re2)
-            {
-                return !(re1 == re2);
-            }
+            public static bool operator ==(RelationshipEntry re1, RelationshipEntry re2) => re1.Equals(re2);
+
+            public static bool operator !=(RelationshipEntry re1, RelationshipEntry re2) => !re1.Equals(re2);
 
             public override int GetHashCode() => _hashCode;
         }
@@ -191,7 +190,7 @@ namespace System.ComponentModel.Design.Serialization
     /// <summary>
     /// This class represents a single relationship between an object and a member.
     /// </summary>
-    public readonly struct MemberRelationship
+    public readonly struct MemberRelationship : IEquatable<MemberRelationship>
     {
         public static readonly MemberRelationship Empty;
 
@@ -222,37 +221,26 @@ namespace System.ComponentModel.Design.Serialization
         /// <summary>
         /// Infrastructure support to make this a first class struct
         /// </summary>
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            return obj is MemberRelationship rel && rel.Owner == Owner && rel.Member == Member;
-        }
+        public override bool Equals([NotNullWhen(true)] object? obj) => obj is MemberRelationship rel && Equals(rel);
 
         /// <summary>
         /// Infrastructure support to make this a first class struct
         /// </summary>
-        public override int GetHashCode()
-        {
-            if (Owner == null)
-            {
-                return base.GetHashCode();
-            }
+        public bool Equals(MemberRelationship other) => other.Owner == Owner && other.Member == Member;
 
-            return Owner.GetHashCode() ^ Member.GetHashCode();
-        }
         /// <summary>
         /// Infrastructure support to make this a first class struct
         /// </summary>
-        public static bool operator ==(MemberRelationship left, MemberRelationship right)
-        {
-            return left.Owner == right.Owner && left.Member == right.Member;
-        }
+        public override int GetHashCode() => Owner is null ? base.GetHashCode() : Owner.GetHashCode() ^ Member.GetHashCode();
 
         /// <summary>
         /// Infrastructure support to make this a first class struct
         /// </summary>
-        public static bool operator !=(MemberRelationship left, MemberRelationship right)
-        {
-            return !(left == right);
-        }
+        public static bool operator ==(MemberRelationship left, MemberRelationship right) => left.Equals(right);
+
+        /// <summary>
+        /// Infrastructure support to make this a first class struct
+        /// </summary>
+        public static bool operator !=(MemberRelationship left, MemberRelationship right) => !left.Equals(right);
     }
 }
index 2190f32..7aa25ce 100644 (file)
@@ -11,7 +11,7 @@ namespace System.ComponentModel
     /// Provides a subset of the <see cref="System.Collections.Specialized.BitVector32"/> surface area, using volatile
     /// operations for reads and interlocked operations for writes.
     /// </summary>
-    internal struct InterlockedBitVector32
+    internal struct InterlockedBitVector32 : IEquatable<InterlockedBitVector32>
     {
         private int _data;
 
@@ -44,7 +44,9 @@ namespace System.ComponentModel
             return previous == 0 ? 1 : previous << 1;
         }
 
-        public override bool Equals([NotNullWhen(true)] object? o) => o is InterlockedBitVector32 vector && _data == vector._data;
+        public override bool Equals([NotNullWhen(true)] object? o) => o is InterlockedBitVector32 other && Equals(other);
+
+        public bool Equals(InterlockedBitVector32 other) => _data == other._data;
 
         public override int GetHashCode() => base.GetHashCode();
     }
index 569f83d..5e66457 100644 (file)
@@ -2737,7 +2737,7 @@ namespace System.Data.SqlTypes
         public SqlAlreadyFilledException(string? message, System.Exception? e) { }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlBinary : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlBinary : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlBinary>
     {
         private object _dummy;
         private int _dummyPrimitive;
@@ -2752,6 +2752,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlBinary Concat(System.Data.SqlTypes.SqlBinary x, System.Data.SqlTypes.SqlBinary y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlBinary x, System.Data.SqlTypes.SqlBinary y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlBinary other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -2777,7 +2778,7 @@ namespace System.Data.SqlTypes
         public override string ToString() { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlBoolean : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlBoolean : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlBoolean>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlBoolean False;
@@ -2796,6 +2797,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(System.Data.SqlTypes.SqlBoolean value) { throw null; }
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlBoolean x, System.Data.SqlTypes.SqlBoolean y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlBoolean other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -2847,7 +2849,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlBoolean Xor(System.Data.SqlTypes.SqlBoolean x, System.Data.SqlTypes.SqlBoolean y) { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlByte : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlByte : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlByte>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlByte MaxValue;
@@ -2864,6 +2866,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlByte Divide(System.Data.SqlTypes.SqlByte x, System.Data.SqlTypes.SqlByte y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlByte x, System.Data.SqlTypes.SqlByte y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlByte other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -2987,7 +2990,7 @@ namespace System.Data.SqlTypes
         BinarySort = 32768,
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlDateTime : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlDateTime : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlDateTime>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlDateTime MaxValue;
@@ -3010,6 +3013,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(System.Data.SqlTypes.SqlDateTime value) { throw null; }
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDateTime x, System.Data.SqlTypes.SqlDateTime y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlDateTime other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3038,7 +3042,7 @@ namespace System.Data.SqlTypes
         public override string ToString() { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlDecimal : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlDecimal : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlDecimal>
     {
         private int _dummyPrimitive;
         public static readonly byte MaxPrecision;
@@ -3068,6 +3072,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlDecimal ConvertToPrecScale(System.Data.SqlTypes.SqlDecimal n, int precision, int scale) { throw null; }
         public static System.Data.SqlTypes.SqlDecimal Divide(System.Data.SqlTypes.SqlDecimal x, System.Data.SqlTypes.SqlDecimal y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDecimal x, System.Data.SqlTypes.SqlDecimal y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlDecimal other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public static System.Data.SqlTypes.SqlDecimal Floor(System.Data.SqlTypes.SqlDecimal n) { throw null; }
         public override int GetHashCode() { throw null; }
@@ -3124,7 +3129,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlDecimal Truncate(System.Data.SqlTypes.SqlDecimal n, int position) { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlDouble : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlDouble : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlDouble>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlDouble MaxValue;
@@ -3139,6 +3144,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlDouble Divide(System.Data.SqlTypes.SqlDouble x, System.Data.SqlTypes.SqlDouble y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDouble x, System.Data.SqlTypes.SqlDouble y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlDouble other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3187,7 +3193,7 @@ namespace System.Data.SqlTypes
         public override string ToString() { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlGuid : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlGuid : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlGuid>
     {
         private object _dummy;
         private int _dummyPrimitive;
@@ -3201,6 +3207,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(System.Data.SqlTypes.SqlGuid value) { throw null; }
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlGuid x, System.Data.SqlTypes.SqlGuid y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlGuid other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3229,7 +3236,7 @@ namespace System.Data.SqlTypes
         public override string ToString() { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlInt16 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlInt16 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlInt16>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlInt16 MaxValue;
@@ -3246,6 +3253,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlInt16 Divide(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlInt16 other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3303,7 +3311,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlInt16 Xor(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlInt32 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlInt32 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlInt32>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlInt32 MaxValue;
@@ -3320,6 +3328,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlInt32 Divide(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlInt32 other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3377,7 +3386,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlInt32 Xor(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlInt64 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlInt64 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlInt64>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlInt64 MaxValue;
@@ -3394,6 +3403,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlInt64 Divide(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlInt64 other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3451,7 +3461,7 @@ namespace System.Data.SqlTypes
         public static System.Data.SqlTypes.SqlInt64 Xor(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlMoney : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlMoney : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlMoney>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlMoney MaxValue;
@@ -3469,6 +3479,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlMoney Divide(System.Data.SqlTypes.SqlMoney x, System.Data.SqlTypes.SqlMoney y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlMoney x, System.Data.SqlTypes.SqlMoney y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlMoney other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3535,7 +3546,7 @@ namespace System.Data.SqlTypes
         public SqlNullValueException(string? message, System.Exception? e) { }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlSingle : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlSingle : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlSingle>
     {
         private int _dummyPrimitive;
         public static readonly System.Data.SqlTypes.SqlSingle MaxValue;
@@ -3551,6 +3562,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlSingle Divide(System.Data.SqlTypes.SqlSingle x, System.Data.SqlTypes.SqlSingle y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlSingle x, System.Data.SqlTypes.SqlSingle y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlSingle other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; }
@@ -3599,7 +3611,7 @@ namespace System.Data.SqlTypes
         public override string ToString() { throw null; }
     }
     [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")]
-    public partial struct SqlString : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable
+    public partial struct SqlString : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable<System.Data.SqlTypes.SqlString>
     {
         private object _dummy;
         private int _dummyPrimitive;
@@ -3630,6 +3642,7 @@ namespace System.Data.SqlTypes
         public int CompareTo(object? value) { throw null; }
         public static System.Data.SqlTypes.SqlString Concat(System.Data.SqlTypes.SqlString x, System.Data.SqlTypes.SqlString y) { throw null; }
         public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlString x, System.Data.SqlTypes.SqlString y) { throw null; }
+        public bool Equals(System.Data.SqlTypes.SqlString other) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; }
         public override int GetHashCode() { throw null; }
         public byte[]? GetNonUnicodeBytes() { throw null; }
index 379035b..7f1a15f 100644 (file)
@@ -5,7 +5,7 @@ using System.Diagnostics;
 
 namespace System.Data
 {
-    internal readonly struct DataKey
+    internal readonly struct DataKey : IEquatable<DataKey>
     {
         private const int maxColumns = 32;
 
@@ -154,7 +154,7 @@ namespace System.Data
             return Equals((DataKey)value);
         }
 
-        internal bool Equals(DataKey value)
+        public bool Equals(DataKey value)
         {
             //check to see if this.columns && key2's columns are equal...
             DataColumn[] column1 = _columns;
index a757be4..f6a45db 100644 (file)
@@ -12,7 +12,7 @@ using System.Diagnostics.CodeAnalysis;
 namespace System.Data.SqlTypes
 {
     [XmlSchemaProvider("GetXsdType")]
-    public struct SqlBinary : INullable, IComparable, IXmlSerializable
+    public struct SqlBinary : INullable, IComparable, IXmlSerializable, IEquatable<SqlBinary>
     {
         // NOTE: If any instance fields change, update SqlTypeWorkarounds type in System.Data.SqlClient.
         private byte[]? _value;
@@ -362,20 +362,15 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlBinary))
-            {
-                return false;
-            }
-
-            SqlBinary i = (SqlBinary)value;
-
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlBinary other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlBinary other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // Hash a byte array.
         // Trailing zeroes/spaces would affect the hash value, so caller needs to
index 1efff18..d7b723f 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlBoolean : INullable, IComparable, IXmlSerializable
+    public struct SqlBoolean : INullable, IComparable, IXmlSerializable, IEquatable<SqlBoolean>
     {
         // m_value: 2 (true), 1 (false), 0 (unknown/Null)
         private byte m_value; // Do not rename (binary serialization)
@@ -465,26 +465,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlBoolean))
-            {
-                return false;
-            }
-
-            SqlBoolean i = (SqlBoolean)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlBoolean other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlBoolean other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index f7c1cdd..3dc5548 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlByte : INullable, IComparable, IXmlSerializable
+    public struct SqlByte : INullable, IComparable, IXmlSerializable, IEquatable<SqlByte>
     {
         private bool m_fNotNull; // false if null. Do not rename (binary serialization)
         private byte m_value; // Do not rename (binary serialization)
@@ -474,26 +474,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlByte))
-            {
-                return false;
-            }
-
-            SqlByte i = (SqlByte)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlByte other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlByte other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 195ca26..1edd44b 100644 (file)
@@ -21,7 +21,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlDateTime : INullable, IComparable, IXmlSerializable
+    public struct SqlDateTime : INullable, IComparable, IXmlSerializable, IEquatable<SqlDateTime>
     {
         private bool m_fNotNull;    // false if null. Do not rename (binary serialization)
         private int m_day;      // Day from 1900/1/1, could be negative. Range: Jan 1 1753 - Dec 31 9999. Do not rename (binary serialization)
@@ -621,26 +621,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlDateTime))
-            {
-                return false;
-            }
-
-            SqlDateTime i = (SqlDateTime)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlDateTime other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlDateTime other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 784d50d..336639f 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Data.SqlTypes
     /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
-    public struct SqlDecimal : INullable, IComparable, IXmlSerializable
+    public struct SqlDecimal : INullable, IComparable, IXmlSerializable, IEquatable<SqlDecimal>
     {
         // data in CSsNumeric in SQL Server
         // BYTE    m_cbLen;                // # of DWORDs + 1 (1 is for sign)
@@ -3278,20 +3278,15 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlDecimal))
-            {
-                return false;
-            }
-
-            SqlDecimal i = (SqlDecimal)value;
-
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlDecimal other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlDecimal other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
         public override int GetHashCode()
index 3f10f94..4cc9ac4 100644 (file)
@@ -19,7 +19,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlDouble : INullable, IComparable, IXmlSerializable
+    public struct SqlDouble : INullable, IComparable, IXmlSerializable, IEquatable<SqlDouble>
     {
         private bool m_fNotNull; // false if null. Do not rename (binary serialization)
         private double m_value; // Do not rename (binary serialization)
@@ -390,26 +390,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlDouble))
-            {
-                return false;
-            }
-
-            SqlDouble i = (SqlDouble)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlDouble other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlDouble other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 8e3c58d..2742c25 100644 (file)
@@ -16,7 +16,7 @@ namespace System.Data.SqlTypes
     [Serializable]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlGuid : INullable, IComparable, IXmlSerializable
+    public struct SqlGuid : INullable, IComparable, IXmlSerializable, IEquatable<SqlGuid>
     {
         private const int SizeOfGuid = 16;
 
@@ -281,26 +281,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlGuid))
-            {
-                return false;
-            }
-
-            SqlGuid i = (SqlGuid)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlGuid other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlGuid other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 5833a00..d3879a0 100644 (file)
@@ -17,7 +17,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlInt16 : INullable, IComparable, IXmlSerializable
+    public struct SqlInt16 : INullable, IComparable, IXmlSerializable, IEquatable<SqlInt16>
     {
         private bool m_fNotNull; // false if null. Do not rename (binary serialization)
         private short m_value; // Do not rename (binary serialization)
@@ -475,26 +475,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlInt16))
-            {
-                return false;
-            }
-
-            SqlInt16 i = (SqlInt16)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlInt16 other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlInt16 other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 271d650..8ce08e7 100644 (file)
@@ -17,7 +17,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlInt32 : INullable, IComparable, IXmlSerializable
+    public struct SqlInt32 : INullable, IComparable, IXmlSerializable, IEquatable<SqlInt32>
     {
         private bool m_fNotNull; // false if null, the default ctor (plain 0) will make it Null. Do not rename (binary serialization)
         private int m_value; // Do not rename (binary serialization)
@@ -490,26 +490,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlInt32))
-            {
-                return false;
-            }
-
-            SqlInt32 i = (SqlInt32)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlInt32 other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlInt32 other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index b7f3367..393945b 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlInt64 : INullable, IComparable, IXmlSerializable
+    public struct SqlInt64 : INullable, IComparable, IXmlSerializable, IEquatable<SqlInt64>
     {
         private bool m_fNotNull; // false if null. Do not rename (binary serialization)
         private long m_value; // Do not rename (binary serialization)
@@ -549,26 +549,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlInt64))
-            {
-                return false;
-            }
-
-            SqlInt64 i = (SqlInt64)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlInt64 other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlInt64 other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 5431c87..64c0d16 100644 (file)
@@ -21,7 +21,7 @@ namespace System.Data.SqlTypes
     /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
-    public struct SqlMoney : INullable, IComparable, IXmlSerializable
+    public struct SqlMoney : INullable, IComparable, IXmlSerializable, IEquatable<SqlMoney>
     {
         // NOTE: If any instance fields change, update SqlTypeWorkarounds type in System.Data.SqlClient.
         private bool _fNotNull; // false if null
@@ -539,27 +539,20 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlMoney))
-            {
-                return false;
-            }
-
-            SqlMoney i = (SqlMoney)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlMoney other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlMoney other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
+        public override int GetHashCode() =>
             // Don't use Value property, because Value will convert to Decimal, which is not necessary.
-            return IsNull ? 0 : _value.GetHashCode();
-        }
+            IsNull ? 0 : _value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index 59f29dc..5fa7562 100644 (file)
@@ -17,7 +17,7 @@ namespace System.Data.SqlTypes
     /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
-    public struct SqlSingle : INullable, IComparable, IXmlSerializable
+    public struct SqlSingle : INullable, IComparable, IXmlSerializable, IEquatable<SqlSingle>
     {
         private bool _fNotNull; // false if null
         private float _value;
@@ -400,26 +400,18 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlSingle))
-            {
-                return false;
-            }
-
-            SqlSingle i = (SqlSingle)value;
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlSingle other && Equals(other);
 
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlSingle other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
-        public override int GetHashCode()
-        {
-            return IsNull ? 0 : Value.GetHashCode();
-        }
+        public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode();
 
         XmlSchema? IXmlSerializable.GetSchema() { return null; }
 
index cac4122..0c22570 100644 (file)
@@ -34,7 +34,7 @@ namespace System.Data.SqlTypes
     [StructLayout(LayoutKind.Sequential)]
     [XmlSchemaProvider("GetXsdType")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public struct SqlString : INullable, IComparable, IXmlSerializable
+    public struct SqlString : INullable, IComparable, IXmlSerializable, IEquatable<SqlString>
     {
         private string? m_value; // Do not rename (binary serialization)
         private CompareInfo? m_cmpInfo; // Do not rename (binary serialization)
@@ -871,20 +871,15 @@ namespace System.Data.SqlTypes
         }
 
         // Compares this instance with a specified object
-        public override bool Equals([NotNullWhen(true)] object? value)
-        {
-            if (!(value is SqlString))
-            {
-                return false;
-            }
-
-            SqlString i = (SqlString)value;
-
-            if (i.IsNull || IsNull)
-                return (i.IsNull && IsNull);
-            else
-                return (this == i).Value;
-        }
+        public override bool Equals([NotNullWhen(true)] object? value) =>
+            value is SqlString other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(SqlString other) =>
+            other.IsNull || IsNull ? other.IsNull && IsNull :
+            (this == other).Value;
 
         // For hashing purpose
         public override int GetHashCode()
index 21a6d95..fd76acf 100644 (file)
@@ -9,7 +9,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Data
 {
-    internal readonly struct IndexField
+    internal readonly struct IndexField : IEquatable<IndexField>
     {
         public readonly DataColumn Column;
         public readonly bool IsDescending; // false = Asc; true = Desc what is default value for this?
@@ -22,15 +22,15 @@ namespace System.Data
             IsDescending = isDescending;
         }
 
-        public static bool operator ==(IndexField if1, IndexField if2) =>
-            if1.Column == if2.Column && if1.IsDescending == if2.IsDescending;
+        public static bool operator ==(IndexField if1, IndexField if2) => if1.Equals(if2);
 
-        public static bool operator !=(IndexField if1, IndexField if2) => !(if1 == if2);
+        public static bool operator !=(IndexField if1, IndexField if2) => !if1.Equals(if2);
 
         // must override Equals if == operator is defined
-        public override bool Equals([NotNullWhen(true)] object? obj) => obj is IndexField ?
-            this == (IndexField)obj :
-            false;
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is IndexField other && Equals(other);
+
+        public bool Equals(IndexField other) => Column == other.Column && IsDescending == other.IsDescending;
 
         // must override GetHashCode if Equals is redefined
         public override int GetHashCode() =>
index 6a631b3..8655d3f 100644 (file)
@@ -122,8 +122,11 @@ namespace System.Data.Tests.SqlTypes
 
             // Equals
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.False(_test3.Equals(_test2));
+            Assert.False(_test3.Equals((object)_test2));
             Assert.True(_test3.Equals(_test1));
+            Assert.True(_test3.Equals((object)_test1));
 
             // NotEquals
             Assert.True(SqlBinary.NotEquals(_test1, _test2).Value);
index 4da63a4..b52f671 100644 (file)
@@ -242,10 +242,14 @@ namespace System.Data.Tests.SqlTypes
             SqlBoolean sqlFalse2 = new SqlBoolean(false);
 
             Assert.True(_sqlTrue.Equals(sqlTrue2));
+            Assert.True(_sqlTrue.Equals((object)sqlTrue2));
             Assert.True(_sqlFalse.Equals(sqlFalse2));
+            Assert.True(_sqlFalse.Equals((object)sqlFalse2));
 
             Assert.False(_sqlTrue.Equals(_sqlFalse));
+            Assert.False(_sqlTrue.Equals((object)_sqlFalse));
             Assert.False(_sqlFalse.Equals(_sqlTrue));
+            Assert.False(_sqlFalse.Equals((object)_sqlTrue));
 
             Assert.False(_sqlTrue.Equals(SqlBoolean.Null));
             Assert.False(_sqlFalse.Equals(SqlBoolean.Null));
index 2ae5976..9af75f4 100644 (file)
@@ -155,9 +155,12 @@ namespace System.Data.Tests.SqlTypes
             SqlByte testByte180II = new SqlByte(180);
 
             Assert.False(testByte0.Equals(testByte158));
+            Assert.False(testByte0.Equals((object)testByte158));
             Assert.False(testByte158.Equals(testByte180));
+            Assert.False(testByte158.Equals((object)testByte180));
             Assert.False(testByte180.Equals(new SqlString("TEST")));
             Assert.True(testByte180.Equals(testByte180II));
+            Assert.True(testByte180.Equals((object)testByte180II));
         }
 
         [Fact]
index 6d3287e..0c835ff 100644 (file)
@@ -175,8 +175,10 @@ namespace System.Data.Tests.SqlTypes
         public void EqualsMethods()
         {
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.False(_test2.Equals(new SqlString("TEST")));
             Assert.True(_test2.Equals(_test3));
+            Assert.True(_test2.Equals((object)_test3));
 
             // Static Equals()-method
             Assert.True(SqlDateTime.Equals(_test2, _test3).Value);
index 6fd72ba..b9807eb 100644 (file)
@@ -225,8 +225,10 @@ namespace System.Data.Tests.SqlTypes
         public void EqualsMethods()
         {
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.False(_test2.Equals(new SqlString("TEST")));
             Assert.True(_test2.Equals(_test3));
+            Assert.True(_test2.Equals((object)_test3));
 
             // Static Equals()-method
             Assert.True(SqlDecimal.Equals(_test2, _test2).Value);
index 4f0856e..db91327 100644 (file)
@@ -134,9 +134,12 @@ namespace System.Data.Tests.SqlTypes
             SqlDouble test22 = new SqlDouble(1.8e180);
 
             Assert.False(test0.Equals(test1));
+            Assert.False(test0.Equals((object)test1));
             Assert.False(test1.Equals(test2));
+            Assert.False(test1.Equals((object)test2));
             Assert.False(test2.Equals(new SqlString("TEST")));
             Assert.True(test2.Equals(test22));
+            Assert.True(test2.Equals((object)test22));
 
             // Static Equals()-method
             Assert.True(SqlDouble.Equals(test2, test22).Value);
index 84dcb3a..4c21e38 100644 (file)
@@ -126,9 +126,12 @@ namespace System.Data.Tests.SqlTypes
         public void EqualsMethods()
         {
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.False(_test2.Equals(_test4));
+            Assert.False(_test2.Equals((object)_test4));
             Assert.False(_test2.Equals(new SqlString("TEST")));
             Assert.True(_test2.Equals(_test3));
+            Assert.True(_test2.Equals((object)_test3));
 
             // Static Equals()-method
             Assert.True(SqlGuid.Equals(_test2, _test3).Value);
index 3c240d6..7c00f48 100644 (file)
@@ -157,9 +157,12 @@ namespace System.Data.Tests.SqlTypes
             SqlInt16 test180II = new SqlInt16(180);
 
             Assert.False(test0.Equals(test158));
+            Assert.False(test0.Equals((object)test158));
             Assert.False(test158.Equals(test180));
+            Assert.False(test158.Equals((object)test180));
             Assert.False(test180.Equals(new SqlString("TEST")));
             Assert.True(test180.Equals(test180II));
+            Assert.True(test180.Equals((object)test180II));
         }
 
         [Fact]
index 601b6a8..ed466fb 100644 (file)
@@ -159,9 +159,12 @@ namespace System.Data.Tests.SqlTypes
             SqlInt64 test180II = new SqlInt64(180);
 
             Assert.False(test0.Equals(test158));
+            Assert.False(test0.Equals((object)test158));
             Assert.False(test158.Equals(test180));
+            Assert.False(test158.Equals((object)test180));
             Assert.False(test180.Equals(new SqlString("TEST")));
             Assert.True(test180.Equals(test180II));
+            Assert.True(test180.Equals((object)test180II));
         }
 
         [Fact]
index 7263021..db99ba4 100644 (file)
@@ -131,7 +131,9 @@ namespace System.Data.Tests.SqlTypes
         public void EqualsMethods()
         {
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.True(_test2.Equals(_test3));
+            Assert.True(_test2.Equals((object)_test3));
             Assert.False(SqlMoney.Equals(_test1, _test2).Value);
             Assert.True(SqlMoney.Equals(_test3, _test2).Value);
         }
index 2c92e08..3ff6c80 100644 (file)
@@ -132,9 +132,12 @@ namespace System.Data.Tests.SqlTypes
             SqlSingle test22 = new SqlSingle(1.8e32);
 
             Assert.False(test0.Equals(test1));
+            Assert.False(test0.Equals((object)test1));
             Assert.False(test1.Equals(test2));
+            Assert.False(test1.Equals((object)test2));
             Assert.False(test2.Equals(new SqlString("TEST")));
             Assert.True(test2.Equals(test22));
+            Assert.True(test2.Equals((object)test22));
 
             // Static Equals()-method
             Assert.True(SqlSingle.Equals(test2, test22).Value);
index 86a4b16..56f8fa5 100644 (file)
@@ -262,9 +262,12 @@ namespace System.Data.Tests.SqlTypes
         public void EqualsMethods()
         {
             Assert.False(_test1.Equals(_test2));
+            Assert.False(_test1.Equals((object)_test2));
             Assert.False(_test3.Equals(_test1));
+            Assert.False(_test3.Equals((object)_test1));
             Assert.False(_test2.Equals(new SqlString("TEST")));
             Assert.True(_test2.Equals(_test3));
+            Assert.True(_test2.Equals((object)_test3));
 
             // Static Equals()-method
             Assert.True(SqlString.Equals(_test2, _test3).Value);
index 9851685..220c3e8 100644 (file)
@@ -6,6 +6,7 @@
   <ItemGroup>
     <Compile Include="System.Diagnostics.PerformanceCounter.cs" Condition="'$(TargetFrameworkIdentifier)' != '.NETFramework'" />
     <Compile Include="System.Diagnostics.PerformanceCounter.netframework.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
+    <Compile Include="System.Diagnostics.PerformanceCounter.netcoreapp.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
     <ProjectReference Include="$(LibrariesProjectRoot)System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
@@ -18,4 +19,4 @@
     <Reference Include="System.Runtime" />
     <Reference Include="System.Runtime.InteropServices" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs
new file mode 100644 (file)
index 0000000..b33f320
--- /dev/null
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ------------------------------------------------------------------------------
+// Changes to this file must follow the https://aka.ms/api-review process.
+// ------------------------------------------------------------------------------
+
+namespace System.Diagnostics
+{
+    public readonly partial struct CounterSample : System.IEquatable<System.Diagnostics.CounterSample>
+    {
+    }
+}
index 28133fe..5ebf58e 100644 (file)
@@ -3,6 +3,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
     <NoWarn>$(NoWarn);CA1847</NoWarn>
+    <NoWarn Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">$(NoWarn);CA1066</NoWarn>
     <Nullable>annotations</Nullable>
     <IsPackable>true</IsPackable>
     <PackageDescription>Provides the System.Diagnostics.PerformanceCounter class, which allows access to Windows performance counters.
index c89df23..315ec5a 100644 (file)
@@ -6,7 +6,7 @@ namespace System.Diagnostics
     /// <summary>
     ///     A struct holding the raw data for a performance counter.
     /// </summary>
-    public readonly struct CounterSample
+    public readonly struct CounterSample : IEquatable<CounterSample>
     {
         private readonly long _rawValue;
         private readonly long _baseValue;
index 0efbf90..60e755e 100644 (file)
@@ -170,7 +170,7 @@ namespace System.Diagnostics.SymbolStore
         BitField = 9,
         NativeSectionOffset = 10,
     }
-    public readonly partial struct SymbolToken
+    public readonly partial struct SymbolToken : System.IEquatable<System.Diagnostics.SymbolStore.SymbolToken>
     {
         private readonly int _dummyPrimitive;
         public SymbolToken(int val) { throw null; }
index b6a894f..8b27f61 100644 (file)
@@ -5,7 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Diagnostics.SymbolStore
 {
-    public readonly struct SymbolToken
+    public readonly struct SymbolToken : IEquatable<SymbolToken>
     {
         private readonly int _token;
 
index f9d987d..1514ee1 100644 (file)
@@ -6,6 +6,10 @@
 
 namespace System.Drawing
 {
+    public partial struct CharacterRange : System.IEquatable<System.Drawing.CharacterRange>
+    {
+        public bool Equals(System.Drawing.CharacterRange other) { throw null; }
+    }
     public sealed partial class Graphics
     {
         public void DrawRectangle(System.Drawing.Pen pen, System.Drawing.RectangleF rect) { }
index 157533b..a0dccdc 100644 (file)
@@ -7,51 +7,43 @@ using System.Runtime.InteropServices;
 namespace System.Drawing
 {
     [StructLayout(LayoutKind.Sequential)]
-    public struct CharacterRange
+    public struct CharacterRange : IEquatable<CharacterRange>
     {
         private int _first;
         private int _length;
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref='CharacterRange'/> class with the specified coordinates.
-        /// </summary>
+        /// <summary>Initializes a new instance of the <see cref='CharacterRange'/> class with the specified coordinates.</summary>
         public CharacterRange(int First, int Length)
         {
             _first = First;
             _length = Length;
         }
 
-        /// <summary>
-        /// Gets the First character position of this <see cref='CharacterRange'/>.
-        /// </summary>
+        /// <summary>Gets the First character position of this <see cref='CharacterRange'/>.</summary>
         public int First
         {
             get => _first;
             set => _first = value;
         }
 
-        /// <summary>
-        /// Gets the Length of this <see cref='CharacterRange'/>.
-        /// </summary>
+        /// <summary>Gets the Length of this <see cref='CharacterRange'/>.</summary>
         public int Length
         {
             get => _length;
             set => _length = value;
         }
 
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            if (!(obj is CharacterRange cr))
-            {
-                return false;
-            }
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is CharacterRange other && Equals(other);
 
-            return First == cr.First && Length == cr.Length;
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(CharacterRange other) => First == other.First && Length == other.Length;
 
         public static bool operator ==(CharacterRange cr1, CharacterRange cr2) => cr1.Equals(cr2);
 
-        public static bool operator !=(CharacterRange cr1, CharacterRange cr2) => !(cr1 == cr2);
+        public static bool operator !=(CharacterRange cr1, CharacterRange cr2) => !cr1.Equals(cr2);
 
         public override int GetHashCode() => HashCode.Combine(First, Length);
     }
index 665a642..bb7b163 100644 (file)
@@ -1,9 +1,12 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
 namespace System.Drawing.Printing
 {
-    internal readonly partial struct TriState
+    internal readonly partial struct TriState : IEquatable<TriState>
     {
         private readonly byte _value; // 0 is "default", not false
 
@@ -11,73 +14,46 @@ namespace System.Drawing.Printing
         public static readonly TriState False = new TriState(1);
         public static readonly TriState True = new TriState(2);
 
-        private TriState(byte value)
-        {
-            _value = value;
-        }
+        private TriState(byte value) => _value = value;
 
-        public bool IsDefault
-        {
-            get { return this == Default; }
-        }
+        public bool IsDefault => this == Default;
 
-        public bool IsFalse
-        {
-            get { return this == False; }
-        }
+        public bool IsFalse => this == False;
 
-        public bool IsNotDefault
-        {
-            get { return this != Default; }
-        }
+        public bool IsNotDefault => this != Default;
 
-        public bool IsTrue
-        {
-            get { return this == True; }
-        }
+        public bool IsTrue => this == True;
 
-        public static bool operator ==(TriState left, TriState right)
-        {
-            return left._value == right._value;
-        }
+        public static bool operator ==(TriState left, TriState right) => left.Equals(right);
 
-        public static bool operator !=(TriState left, TriState right)
-        {
-            return !(left == right);
-        }
+        public static bool operator !=(TriState left, TriState right) => !left.Equals(right);
 
-        public override bool Equals(object? o)
+        public override bool Equals([NotNullWhen(true)] object? o)
         {
-            TriState state = (TriState)o!;
-            return _value == state._value;
+            Debug.Assert(o is TriState);
+            return Equals((TriState)o);
         }
 
-        public override int GetHashCode()
-        {
-            return _value;
-        }
+        public bool Equals(TriState other) => _value == other._value;
 
-        public static implicit operator TriState(bool value)
-        {
-            return (value) ? True : False;
-        }
+        public override int GetHashCode() => _value;
+
+        public static implicit operator TriState(bool value) => value ? True : False;
 
         public static explicit operator bool(TriState value)
         {
             if (value.IsDefault)
+            {
                 throw new InvalidCastException(SR.TriStateCompareError);
-            else
-                return (value == TriState.True);
-        }
+            }
 
-        /// <summary>
-        /// Provides some interesting information about the TriState in String form.
-        /// </summary>
-        public override string ToString()
-        {
-            if (this == Default) return "Default";
-            else if (this == False) return "False";
-            else return "True";
+            return (value == TriState.True);
         }
+
+        /// <summary>Provides some interesting information about the TriState in String form.</summary>
+        public override string ToString() =>
+            this == Default ? "Default" :
+            this == False ? "False" :
+            "True";
     }
 }
index 7147cb8..989ee85 100644 (file)
@@ -84,6 +84,7 @@ namespace System.Drawing.Tests
             Assert.Equal(expected, range.Equals(obj));
             if (obj is CharacterRange otherRange)
             {
+                Assert.Equal(expected, range.Equals(otherRange));
                 Assert.Equal(expected, range == otherRange);
                 Assert.Equal(!expected, range != otherRange);
                 Assert.Equal(expected, range.GetHashCode().Equals(otherRange.GetHashCode()));
index 15c8994..5825a14 100644 (file)
@@ -611,7 +611,9 @@ namespace System.IO.Packaging
         /// to reduce the parsing and number of allocations for Strings and Uris
         /// we cache the results after parsing.
         /// </summary>
+ #pragma warning disable CA1067 // Override Equals because it implements IEquatable<T>; not overriding to avoid possible regressions in code that's working
         internal sealed class ValidatedPartUri : Uri, IComparable<ValidatedPartUri>, IEquatable<ValidatedPartUri>
+#pragma warning restore CA1067
         {
             //------------------------------------------------------
             //
index d078d82..f42254d 100644 (file)
@@ -44,7 +44,7 @@ namespace System.Linq.Expressions.Interpreter
             string.Create(CultureInfo.InvariantCulture, $"{Index}: {(IsBoxed ? "boxed" : null)} {(InClosure ? "in closure" : null)}");
     }
 
-    internal readonly struct LocalDefinition
+    internal readonly struct LocalDefinition : IEquatable<LocalDefinition>
     {
         internal LocalDefinition(int localIndex, ParameterExpression parameter)
         {
@@ -53,27 +53,14 @@ namespace System.Linq.Expressions.Interpreter
         }
 
         public int Index { get; }
+
         public ParameterExpression Parameter { get; }
 
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            if (obj is LocalDefinition)
-            {
-                LocalDefinition other = (LocalDefinition)obj;
-                return other.Index == Index && other.Parameter == Parameter;
-            }
+        public override bool Equals([NotNullWhen(true)] object? obj) => obj is LocalDefinition other && Equals(other);
 
-            return false;
-        }
+        public bool Equals(LocalDefinition other) => other.Index == Index && other.Parameter == Parameter;
 
-        public override int GetHashCode()
-        {
-            if (Parameter == null)
-            {
-                return 0;
-            }
-            return Parameter.GetHashCode() ^ Index.GetHashCode();
-        }
+        public override int GetHashCode() => Parameter is null ? 0 : Parameter.GetHashCode() ^ Index.GetHashCode();
     }
 
     internal sealed class LocalVariables
index 212c063..e813cca 100644 (file)
@@ -74,13 +74,14 @@ namespace System.Net.Sockets
         [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
         AddressListSort = (long)3355443225,
     }
-    public partial struct IPPacketInformation
+    public partial struct IPPacketInformation : System.IEquatable<System.Net.Sockets.IPPacketInformation>
     {
         private object _dummy;
         private int _dummyPrimitive;
         public System.Net.IPAddress Address { get { throw null; } }
         public int Interface { get { throw null; } }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? comparand) { throw null; }
+        public bool Equals(System.Net.Sockets.IPPacketInformation other) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.Net.Sockets.IPPacketInformation packetInformation1, System.Net.Sockets.IPPacketInformation packetInformation2) { throw null; }
         public static bool operator !=(System.Net.Sockets.IPPacketInformation packetInformation1, System.Net.Sockets.IPPacketInformation packetInformation2) { throw null; }
index 06d4eca..b0597b6 100644 (file)
@@ -5,7 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Net.Sockets
 {
-    public struct IPPacketInformation
+    public struct IPPacketInformation : IEquatable<IPPacketInformation>
     {
         private readonly IPAddress _address;
         private readonly int _networkInterface;
@@ -16,41 +16,27 @@ namespace System.Net.Sockets
             _networkInterface = networkInterface;
         }
 
-        public IPAddress Address
-        {
-            get
-            {
-                return _address;
-            }
-        }
+        public IPAddress Address => _address;
 
-        public int Interface
-        {
-            get
-            {
-                return _networkInterface;
-            }
-        }
+        public int Interface => _networkInterface;
 
-        public static bool operator ==(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2)
-        {
-            return packetInformation1._networkInterface == packetInformation2._networkInterface &&
-                ((packetInformation1._address == null && packetInformation2._address == null) ||
-                (packetInformation1._address != null && packetInformation1._address.Equals(packetInformation2._address)));
-        }
+        public static bool operator ==(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) =>
+            packetInformation1.Equals(packetInformation2);
 
-        public static bool operator !=(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2)
-        {
-            return !(packetInformation1 == packetInformation2);
-        }
+        public static bool operator !=(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) =>
+            !packetInformation1.Equals(packetInformation2);
 
         public override bool Equals([NotNullWhen(true)] object? comparand) =>
-            comparand is IPPacketInformation other && this == other;
+            comparand is IPPacketInformation other && Equals(other);
 
-        public override int GetHashCode()
-        {
-            return unchecked(_networkInterface.GetHashCode() * (int)0xA5555529) +
-                (_address == null ? 0 : _address.GetHashCode());
-        }
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(IPPacketInformation other) =>
+            _networkInterface == other._networkInterface &&
+            (_address is null ? other._address is null : _address.Equals(other._address));
+
+        public override int GetHashCode() =>
+            unchecked(_networkInterface.GetHashCode() * (int)0xA5555529) + (_address?.GetHashCode() ?? 0);
     }
 }
index 443924b..19dbc7f 100644 (file)
@@ -13,7 +13,10 @@ namespace System.Net.Sockets.Tests
         public void Equals_DefaultValues_Success()
         {
             Assert.Equal(default(IPPacketInformation), default(IPPacketInformation));
+
             Assert.True(default(IPPacketInformation) == default(IPPacketInformation));
+            Assert.True(default(IPPacketInformation).Equals(default(IPPacketInformation)));
+
             Assert.False(default(IPPacketInformation) != default(IPPacketInformation));
         }
 
@@ -31,10 +34,14 @@ namespace System.Net.Sockets.Tests
 
             Assert.Equal(packetInfo, packetInfoCopy);
             Assert.True(packetInfo == packetInfoCopy);
+            Assert.True(packetInfo.Equals(packetInfoCopy));
+            Assert.True(packetInfo.Equals((object)packetInfoCopy));
             Assert.False(packetInfo != packetInfoCopy);
 
             Assert.NotEqual(default, packetInfo);
             Assert.False(packetInfo == default(IPPacketInformation));
+            Assert.False(packetInfo.Equals(default(IPPacketInformation)));
+            Assert.False(packetInfo.Equals((object)default(IPPacketInformation)));
             Assert.True(packetInfo != default(IPPacketInformation));
 
             int ignored = packetInfo.Interface; // just make sure it doesn't throw, nothing else to verify
index 06c31c4..2d6c817 100644 (file)
@@ -26,8 +26,16 @@ namespace System
     // (ie, users could assign a new value to the old location).
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+#pragma warning disable CA1066 // adding IEquatable<T> implementation could change semantics of code like that in xunit that queries for IEquatable vs enumerating contents
     public readonly struct ArraySegment<T> : IList<T>, IReadOnlyList<T>
+#pragma warning restore CA1066
     {
+        // ArraySegment<T> doesn't implement IEquatable<T>, even though it provides a strongly-typed
+        // Equals(T), as that results in different comparison semantics than comparing item-by-item
+        // the elements returned from its IEnumerable<T> implementation.  This then is a breaking change
+        // for usage like that in xunit's Assert.Equal, which will prioritize using an instance's IEquatable<T>
+        // over its IEnumerable<T>.
+
         // Do not replace the array allocation with Array.Empty. We don't want to have the overhead of
         // instantiating another generic type in addition to ArraySegment<T> for new type parameters.
 #pragma warning disable CA1825
@@ -120,7 +128,7 @@ namespace System
         }
 
         public override bool Equals([NotNullWhen(true)] object? obj) =>
-            obj is ArraySegment<T> && Equals((ArraySegment<T>)obj);
+            obj is ArraySegment<T> other && Equals(other);
 
         public bool Equals(ArraySegment<T> obj) =>
             obj._array == _array && obj._offset == _offset && obj._count == _count;
index c3994e6..b1aaccd 100644 (file)
@@ -15,7 +15,7 @@ namespace System.Diagnostics.Tracing
 #if ES_BUILD_STANDALONE
     [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
 #endif
-    internal struct EventDescriptor
+    internal readonly struct EventDescriptor : IEquatable<EventDescriptor>
     {
         #region private
         [FieldOffset(0)]
index d9735f0..f40830e 100644 (file)
@@ -47,6 +47,8 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Internal.Runtime.CompilerServices;
 
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 namespace System
 {
     // xxHash32 is used for the hash code.
index 7fb1803..3555783 100644 (file)
@@ -11,6 +11,8 @@ using System.Runtime.Versioning;
 using Internal.Runtime.CompilerServices;
 
 #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 #if TARGET_64BIT
 using nint_t = System.Int64;
 #else
index 0fa9141..089f970 100644 (file)
@@ -4,6 +4,8 @@
 using System.Collections.Generic;
 using System.Runtime.Versioning;
 
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 namespace System
 {
     // Because we have special type system support that says a boxed Nullable<T>
index 9699e14..b2baa77 100644 (file)
@@ -1,9 +1,11 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System.Diagnostics.CodeAnalysis;
+
 namespace System.Reflection
 {
-    public readonly partial struct CustomAttributeNamedArgument
+    public readonly partial struct CustomAttributeNamedArgument : IEquatable<CustomAttributeNamedArgument>
     {
         public static bool operator ==(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right) => left.Equals(right);
         public static bool operator !=(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right) => !left.Equals(right);
@@ -46,10 +48,15 @@ namespace System.Reflection
             return base.GetHashCode();
         }
 
-        public override bool Equals(object? obj)
-        {
-            return obj == (object)this;
-        }
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is CustomAttributeNamedArgument other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(CustomAttributeNamedArgument other) =>
+            _memberInfo == other._memberInfo &&
+            _value == other._value;
 
         internal Type ArgumentType =>
             _memberInfo is FieldInfo fi ?
index 3198e9f..b0e306a 100644 (file)
@@ -2,11 +2,12 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Text;
 
 namespace System.Reflection
 {
-    public readonly partial struct CustomAttributeTypedArgument
+    public readonly partial struct CustomAttributeTypedArgument : IEquatable<CustomAttributeTypedArgument>
     {
         public static bool operator ==(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right) => left.Equals(right);
         public static bool operator !=(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right) => !left.Equals(right);
@@ -86,7 +87,13 @@ namespace System.Reflection
         }
 
         public override int GetHashCode() => base.GetHashCode();
-        public override bool Equals(object? obj) => obj == (object)this;
+
+        public override bool Equals([NotNullWhen(true)] object? obj) => obj is CustomAttributeTypedArgument cata && Equals(cata);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(CustomAttributeTypedArgument other) => _value == other._value && _argumentType == other._argumentType;
 
         public Type ArgumentType => _argumentType;
         public object? Value => _value;
index 8a80faa..92d42d6 100644 (file)
@@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
 
 namespace System.Runtime.InteropServices
 {
-    public readonly struct ArrayWithOffset
+    public readonly struct ArrayWithOffset : IEquatable<ArrayWithOffset>
     {
         private readonly object? m_array;
         private readonly int m_offset;
@@ -52,7 +52,7 @@ namespace System.Runtime.InteropServices
 
         public override bool Equals([NotNullWhen(true)] object? obj)
         {
-            return obj is ArrayWithOffset && Equals((ArrayWithOffset)obj);
+            return obj is ArrayWithOffset awo && Equals(awo);
         }
 
         public bool Equals(ArrayWithOffset obj)
index 579633d..a1c849b 100644 (file)
@@ -23,7 +23,7 @@ namespace System.Runtime.InteropServices
     /// Pinned - same as Normal, but allows the address of the actual object to be taken.
     /// </remarks>
     [StructLayout(LayoutKind.Sequential)]
-    public partial struct GCHandle
+    public partial struct GCHandle : IEquatable<GCHandle>
     {
         // The actual integer handle value that the EE uses internally.
         private IntPtr _handle;
@@ -163,7 +163,12 @@ namespace System.Runtime.InteropServices
 
         public override int GetHashCode() => _handle.GetHashCode();
 
-        public override bool Equals([NotNullWhen(true)] object? o) => o is GCHandle && _handle == ((GCHandle)o)._handle;
+        public override bool Equals([NotNullWhen(true)] object? o) => o is GCHandle other && Equals(other);
+
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(GCHandle other) => _handle == other._handle;
 
         public static bool operator ==(GCHandle a, GCHandle b) => (nint)a._handle == (nint)b._handle;
 
index 3501457..1b3b86c 100644 (file)
@@ -3,6 +3,8 @@
 
 using System.Diagnostics.CodeAnalysis;
 
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 namespace System.Runtime.Serialization
 {
     public readonly struct StreamingContext
index ab03e12..27f29cb 100644 (file)
@@ -27,7 +27,7 @@ namespace System.Threading
     /// </para>
     /// </remarks>
     [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")]
-    public readonly struct CancellationToken
+    public readonly struct CancellationToken : IEquatable<CancellationToken>
     {
         // The backing TokenSource.
         // if null, it implicitly represents the same thing as new CancellationToken(false).
index 6b6b86e..25a229c 100644 (file)
@@ -242,7 +242,7 @@ namespace System.Threading
             }
         }
 
-        private struct Counts
+        private struct Counts : IEquatable<Counts>
         {
             private const byte SignalCountShift = 0;
             private const byte WaiterCountShift = 32;
@@ -350,10 +350,11 @@ namespace System.Threading
             public Counts InterlockedCompareExchange(Counts newCounts, Counts oldCounts) =>
                 new Counts(Interlocked.CompareExchange(ref _data, newCounts._data, oldCounts._data));
 
-            public static bool operator ==(Counts lhs, Counts rhs) => lhs._data == rhs._data;
-            public static bool operator !=(Counts lhs, Counts rhs) => lhs._data != rhs._data;
+            public static bool operator ==(Counts lhs, Counts rhs) => lhs.Equals(rhs);
+            public static bool operator !=(Counts lhs, Counts rhs) => !lhs.Equals(rhs);
 
-            public override bool Equals([NotNullWhen(true)] object? obj) => obj is Counts counts && _data == counts._data;
+            public override bool Equals([NotNullWhen(true)] object? obj) => obj is Counts other && Equals(other);
+            public bool Equals(Counts other) => _data == other._data;
             public override int GetHashCode() => (int)_data + (int)(_data >> 32);
         }
 
index 43aa0fc..3242f16 100644 (file)
@@ -11,7 +11,7 @@ namespace System.Threading
         /// <summary>
         /// Tracks information on the number of threads we want/have in different states in our thread pool.
         /// </summary>
-        private struct ThreadCounts
+        private struct ThreadCounts : IEquatable<ThreadCounts>
         {
             // SOS's ThreadPool command depends on this layout
             private const byte NumProcessingWorkShift = 0;
@@ -126,7 +126,8 @@ namespace System.Threading
             public static bool operator ==(ThreadCounts lhs, ThreadCounts rhs) => lhs._data == rhs._data;
             public static bool operator !=(ThreadCounts lhs, ThreadCounts rhs) => lhs._data != rhs._data;
 
-            public override bool Equals([NotNullWhen(true)] object? obj) => obj is ThreadCounts other && _data == other._data;
+            public override bool Equals([NotNullWhen(true)] object? obj) => obj is ThreadCounts other && Equals(other);
+            public bool Equals(ThreadCounts other) => _data == other._data;
             public override int GetHashCode() => (int)_data + (int)(_data >> 32);
         }
     }
index 8c58896..8a5f1d8 100644 (file)
@@ -58,7 +58,7 @@ namespace System.Threading
         /// <summary>
         /// Tracks thread count information that is used when the <code>EnableWorkerTracking</code> config option is enabled.
         /// </summary>
-        private struct CountsOfThreadsProcessingUserCallbacks
+        private struct CountsOfThreadsProcessingUserCallbacks : IEquatable<CountsOfThreadsProcessingUserCallbacks>
         {
             private const byte CurrentShift = 0;
             private const byte HighWatermarkShift = 16;
@@ -114,13 +114,16 @@ namespace System.Threading
 
             public static bool operator ==(
                 CountsOfThreadsProcessingUserCallbacks lhs,
-                CountsOfThreadsProcessingUserCallbacks rhs) => lhs._data == rhs._data;
+                CountsOfThreadsProcessingUserCallbacks rhs) => lhs.Equals(rhs);
             public static bool operator !=(
                 CountsOfThreadsProcessingUserCallbacks lhs,
-                CountsOfThreadsProcessingUserCallbacks rhs) => lhs._data != rhs._data;
+                CountsOfThreadsProcessingUserCallbacks rhs) => !lhs.Equals(rhs);
 
             public override bool Equals([NotNullWhen(true)] object? obj) =>
-                obj is CountsOfThreadsProcessingUserCallbacks other && _data == other._data;
+                obj is CountsOfThreadsProcessingUserCallbacks other && Equals(other);
+
+            public bool Equals(CountsOfThreadsProcessingUserCallbacks other) => _data == other._data;
+
             public override int GetHashCode() => (int)_data;
         }
     }
index 6f53ab7..7c754b4 100644 (file)
@@ -56,6 +56,12 @@ namespace System
                 _daylightTransitionEnd.Equals(other._daylightTransitionEnd) &&
                 _daylightTransitionStart.Equals(other._daylightTransitionStart);
 
+            /// <summary>Indicates whether the current instance is equal to another instance.</summary>
+            /// <param name="obj">An instance to compare with this instance.</param>
+            /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+            public override bool Equals([NotNullWhen(true)] object? obj) =>
+                obj is AdjustmentRule other && Equals(other);
+
             public override int GetHashCode() => _dateStart.GetHashCode();
 
             private AdjustmentRule(
index bc7859c..12a2dce 100644 (file)
@@ -11,6 +11,8 @@ using System.Runtime.Versioning;
 using Internal.Runtime.CompilerServices;
 
 #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 #if TARGET_64BIT
 using nuint_t = System.UInt64;
 #else
index 074f795..33d1e3d 100644 (file)
@@ -59,7 +59,7 @@ namespace System.Xml
         };
 
         // Note: also used by XmlBinaryWriter
-        internal struct QName
+        internal struct QName : IEquatable<QName>
         {
             public string prefix;
             public string localname;
@@ -95,45 +95,26 @@ namespace System.Xml
                     throw new XmlException(SR.XmlBinary_NoRemapPrefix, new string[] { prefix, this.namespaceUri, namespaceUri });
             }
 
-            public override int GetHashCode()
-            {
-                return this.prefix.GetHashCode() ^ this.localname.GetHashCode();
-            }
+            public int GetNSHashCode() =>
+                HashCode.Combine(this.namespaceUri, this.localname);
 
-            public int GetNSHashCode()
-            {
-                return HashCode.Combine(this.namespaceUri, this.localname);
-            }
+            public override int GetHashCode() =>
+                this.prefix.GetHashCode() ^ this.localname.GetHashCode();
 
+            public override bool Equals([NotNullWhen(true)] object? other) =>
+                other is QName qname && Equals(qname);
 
-            public override bool Equals([NotNullWhen(true)] object? other)
-            {
-                if (other is QName that)
-                {
-                    return this == that;
-                }
-                return false;
-            }
+            public bool Equals(QName other) =>
+                prefix == other.prefix &&
+                localname == other.localname &&
+                namespaceUri == other.namespaceUri;
 
-            public override string ToString()
-            {
-                if (prefix.Length == 0)
-                    return this.localname;
-                else
-                    return $"{this.prefix}:{this.localname}";
-            }
+            public static bool operator ==(QName a, QName b) => a.Equals(b);
 
-            public static bool operator ==(QName a, QName b)
-            {
-                return ((a.prefix == b.prefix)
-                    && (a.localname == b.localname)
-                    && (a.namespaceUri == b.namespaceUri));
-            }
+            public static bool operator !=(QName a, QName b) => !a.Equals(b);
 
-            public static bool operator !=(QName a, QName b)
-            {
-                return !(a == b);
-            }
+            public override string ToString() =>
+                prefix.Length == 0 ? localname : $"{this.prefix}:{this.localname}";
         };
 
         private struct ElemInfo
index 8e3e1a4..33b4fe9 100644 (file)
@@ -7,49 +7,34 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Xml.Xsl
 {
-    internal struct Int32Pair
+    internal readonly struct Int32Pair : IEquatable<Int32Pair>
     {
-        private readonly int _left;
-        private readonly int _right;
-
         public Int32Pair(int left, int right)
         {
-            _left = left;
-            _right = right;
+            Left = left;
+            Right = right;
         }
 
-        public int Left { get { return _left; } }
-        public int Right { get { return _right; } }
+        public int Left { get; }
+        public int Right { get; }
 
-        public override bool Equals([NotNullWhen(true)] object? other)
-        {
-            if (other is Int32Pair)
-            {
-                Int32Pair o = (Int32Pair)other;
-                return _left == o._left && _right == o._right;
-            }
+        public override bool Equals([NotNullWhen(true)] object? other) =>
+            other is Int32Pair o && Equals(o);
 
-            return false;
-        }
+        public bool Equals(Int32Pair other) => Left == other.Left && Right == other.Right;
 
-        public override int GetHashCode()
-        {
-            return _left.GetHashCode() ^ _right.GetHashCode();
-        }
+        public override int GetHashCode() => Left.GetHashCode() ^ Right.GetHashCode();
     }
 
-    internal struct StringPair
+    internal readonly struct StringPair
     {
-        private readonly string _left;
-        private readonly string _right;
-
         public StringPair(string left, string right)
         {
-            _left = left;
-            _right = right;
+            Left = left;
+            Right = right;
         }
 
-        public string Left { get { return _left; } }
-        public string Right { get { return _right; } }
+        public string Left { get; }
+        public string Right { get; }
     }
 }
index 1046765..a95ce13 100644 (file)
@@ -11,7 +11,7 @@ namespace System.Xml.Xsl
     /// Cardinality of part of XmlQueryType
     /// struct is being used because enum doesn't allow members
     /// </summary>
-    internal struct XmlQueryCardinality
+    internal readonly struct XmlQueryCardinality : IEquatable<XmlQueryCardinality>
     {
         private readonly int _value;
 
index e4eab06..f9cc0fd 100644 (file)
@@ -13,7 +13,7 @@ using System.Threading;
 
 namespace System.Runtime.Caching
 {
-    internal struct ExpiresEntryRef
+    internal readonly struct ExpiresEntryRef : IEquatable<ExpiresEntryRef>
     {
         internal static readonly ExpiresEntryRef INVALID = new ExpiresEntryRef(0, 0);
 
@@ -31,55 +31,18 @@ namespace System.Runtime.Caching
             _ref = ((((uint)pageIndex) << PAGE_SHIFT) | (((uint)(entryIndex)) & ENTRY_MASK));
         }
 
-        public override bool Equals(object value)
-        {
-            if (value is ExpiresEntryRef)
-            {
-                return _ref == ((ExpiresEntryRef)value)._ref;
-            }
+        public override bool Equals(object value) => value is ExpiresEntryRef other && Equals(other);
 
-            return false;
-        }
+        public bool Equals(ExpiresEntryRef other) => _ref == other._ref;
 
-        public static bool operator !=(ExpiresEntryRef r1, ExpiresEntryRef r2)
-        {
-            return r1._ref != r2._ref;
-        }
-        public static bool operator ==(ExpiresEntryRef r1, ExpiresEntryRef r2)
-        {
-            return r1._ref == r2._ref;
-        }
+        public static bool operator ==(ExpiresEntryRef r1, ExpiresEntryRef r2) => r1.Equals(r2);
+        public static bool operator !=(ExpiresEntryRef r1, ExpiresEntryRef r2) => !r1.Equals(r2);
 
-        public override int GetHashCode()
-        {
-            return (int)_ref;
-        }
+        public override int GetHashCode() => (int)_ref;
 
-        internal int PageIndex
-        {
-            get
-            {
-                int result = (int)(_ref >> PAGE_SHIFT);
-                return result;
-            }
-        }
-
-        internal int Index
-        {
-            get
-            {
-                int result = (int)(_ref & ENTRY_MASK);
-                return result;
-            }
-        }
-
-        internal bool IsInvalid
-        {
-            get
-            {
-                return _ref == 0;
-            }
-        }
+        internal int PageIndex => (int)(_ref >> PAGE_SHIFT);
+        internal int Index => (int)(_ref & ENTRY_MASK);
+        internal bool IsInvalid => _ref == 0;
     }
 
     [StructLayout(LayoutKind.Explicit)]
index 73ed9f3..7b7ea64 100644 (file)
@@ -13,7 +13,7 @@ using System.Threading;
 
 namespace System.Runtime.Caching
 {
-    internal struct UsageEntryRef
+    internal readonly struct UsageEntryRef : IEquatable<UsageEntryRef>
     {
         internal static readonly UsageEntryRef INVALID = new UsageEntryRef(0, 0);
 
@@ -31,38 +31,18 @@ namespace System.Runtime.Caching
             _ref = ((((uint)pageIndex) << PAGE_SHIFT) | (((uint)(entryIndex)) & ENTRY_MASK));
         }
 
-        public override bool Equals(object value)
-        {
-            if (value is UsageEntryRef)
-            {
-                return _ref == ((UsageEntryRef)value)._ref;
-            }
+        public override bool Equals(object value) =>
+            value is UsageEntryRef other && Equals(other);
 
-            return false;
-        }
-        public static bool operator ==(UsageEntryRef r1, UsageEntryRef r2)
-        {
-            return r1._ref == r2._ref;
-        }
+        public bool Equals(UsageEntryRef other) => _ref == other._ref;
 
-        public static bool operator !=(UsageEntryRef r1, UsageEntryRef r2)
-        {
-            return r1._ref != r2._ref;
-        }
+        public static bool operator ==(UsageEntryRef r1, UsageEntryRef r2) => r1.Equals(r2);
 
-        public override int GetHashCode()
-        {
-            return (int)_ref;
-        }
+        public static bool operator !=(UsageEntryRef r1, UsageEntryRef r2) => !r1.Equals(r2);
 
-        internal int PageIndex
-        {
-            get
-            {
-                int result = (int)(_ref >> PAGE_SHIFT);
-                return result;
-            }
-        }
+        public override int GetHashCode() => (int)_ref;
+
+        internal int PageIndex => (int)(_ref >> PAGE_SHIFT);
 
         internal int Ref1Index
         {
@@ -84,29 +64,11 @@ namespace System.Runtime.Caching
             }
         }
 
-        internal bool IsRef1
-        {
-            get
-            {
-                return ((int)(sbyte)(_ref & ENTRY_MASK)) > 0;
-            }
-        }
+        internal bool IsRef1 => ((int)(sbyte)(_ref & ENTRY_MASK)) > 0;
 
-        internal bool IsRef2
-        {
-            get
-            {
-                return ((int)(sbyte)(_ref & ENTRY_MASK)) < 0;
-            }
-        }
+        internal bool IsRef2 => ((int)(sbyte)(_ref & ENTRY_MASK)) < 0;
 
-        internal bool IsInvalid
-        {
-            get
-            {
-                return _ref == 0;
-            }
-        }
+        internal bool IsInvalid => _ref == 0;
     }
 
     internal struct UsageEntryLink
index 901b763..e58de5b 100644 (file)
@@ -98,7 +98,7 @@ namespace System.Runtime.InteropServices
     {
         public AllowReversePInvokeCallsAttribute() { }
     }
-    public readonly partial struct ArrayWithOffset
+    public readonly partial struct ArrayWithOffset : System.IEquatable<System.Runtime.InteropServices.ArrayWithOffset>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
index bf5ec17..8a79b7a 100644 (file)
@@ -138,6 +138,7 @@ namespace System.Runtime.InteropServices.Tests
                 Assert.Equal(expected, handle.Equals(other));
                 if (other is GCHandle otherHandle)
                 {
+                    Assert.Equal(expected, handle.Equals(otherHandle));
                     Assert.Equal(expected, handle == otherHandle);
                     Assert.Equal(!expected, handle != otherHandle);
                 }
index c57c5b1..57c9f83 100644 (file)
@@ -4826,7 +4826,7 @@ namespace System
         public MissingMethodException(string? className, string? methodName) { }
         public override string Message { get { throw null; } }
     }
-    public partial struct ModuleHandle
+    public partial struct ModuleHandle : System.IEquatable<System.ModuleHandle>
     {
         private object _dummy;
         private int _dummyPrimitive;
@@ -6367,6 +6367,7 @@ namespace System
             public static System.TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(System.DateTime dateStart, System.DateTime dateEnd, System.TimeSpan daylightDelta, System.TimeZoneInfo.TransitionTime daylightTransitionStart, System.TimeZoneInfo.TransitionTime daylightTransitionEnd) { throw null; }
             public static System.TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(System.DateTime dateStart, System.DateTime dateEnd, System.TimeSpan daylightDelta, System.TimeZoneInfo.TransitionTime daylightTransitionStart, System.TimeZoneInfo.TransitionTime daylightTransitionEnd, System.TimeSpan baseUtcOffsetDelta) { throw null; }
             public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.TimeZoneInfo.AdjustmentRule? other) { throw null; }
+            public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
             public override int GetHashCode() { throw null; }
             void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { }
             void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
@@ -11648,7 +11649,7 @@ namespace System.Reflection
         public CustomAttributeFormatException(string? message) { }
         public CustomAttributeFormatException(string? message, System.Exception? inner) { }
     }
-    public readonly partial struct CustomAttributeNamedArgument
+    public readonly partial struct CustomAttributeNamedArgument : System.IEquatable<System.Reflection.CustomAttributeNamedArgument>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
@@ -11658,13 +11659,14 @@ namespace System.Reflection
         public System.Reflection.MemberInfo MemberInfo { get { throw null; } }
         public string MemberName { get { throw null; } }
         public System.Reflection.CustomAttributeTypedArgument TypedValue { get { throw null; } }
-        public override bool Equals(object? obj) { throw null; }
+        public bool Equals(System.Reflection.CustomAttributeNamedArgument other) { throw null; }
+        public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.Reflection.CustomAttributeNamedArgument left, System.Reflection.CustomAttributeNamedArgument right) { throw null; }
         public static bool operator !=(System.Reflection.CustomAttributeNamedArgument left, System.Reflection.CustomAttributeNamedArgument right) { throw null; }
         public override string ToString() { throw null; }
     }
-    public readonly partial struct CustomAttributeTypedArgument
+    public readonly partial struct CustomAttributeTypedArgument : System.IEquatable<System.Reflection.CustomAttributeTypedArgument>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
@@ -11672,7 +11674,8 @@ namespace System.Reflection
         public CustomAttributeTypedArgument(System.Type argumentType, object? value) { throw null; }
         public System.Type ArgumentType { get { throw null; } }
         public object? Value { get { throw null; } }
-        public override bool Equals(object? obj) { throw null; }
+        public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
+        public bool Equals(System.Reflection.CustomAttributeTypedArgument other) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.Reflection.CustomAttributeTypedArgument left, System.Reflection.CustomAttributeTypedArgument right) { throw null; }
         public static bool operator !=(System.Reflection.CustomAttributeTypedArgument left, System.Reflection.CustomAttributeTypedArgument right) { throw null; }
@@ -13493,7 +13496,7 @@ namespace System.Runtime.InteropServices
         public FieldOffsetAttribute(int offset) { }
         public int Value { get { throw null; } }
     }
-    public partial struct GCHandle
+    public partial struct GCHandle : System.IEquatable<System.Runtime.InteropServices.GCHandle>
     {
         private int _dummyPrimitive;
         public bool IsAllocated { get { throw null; } }
@@ -13502,6 +13505,7 @@ namespace System.Runtime.InteropServices
         public static System.Runtime.InteropServices.GCHandle Alloc(object? value) { throw null; }
         public static System.Runtime.InteropServices.GCHandle Alloc(object? value, System.Runtime.InteropServices.GCHandleType type) { throw null; }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; }
+        public bool Equals(System.Runtime.InteropServices.GCHandle other) { throw null; }
         public void Free() { }
         public static System.Runtime.InteropServices.GCHandle FromIntPtr(System.IntPtr value) { throw null; }
         public override int GetHashCode() { throw null; }
@@ -14770,7 +14774,7 @@ namespace System.Text.Unicode
 }
 namespace System.Threading
 {
-    public readonly partial struct CancellationToken
+    public readonly partial struct CancellationToken : System.IEquatable<System.Threading.CancellationToken>
     {
         private readonly object _dummy;
         private readonly int _dummyPrimitive;
index 4460797..c406e36 100644 (file)
@@ -53,6 +53,28 @@ namespace System.Reflection.Tests
         }
 
         [Fact]
+        public static void Test_CustomAttributeTypedArgument_Equals()
+        {
+            Type t = typeof(MyClass);
+            foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(t))
+            {
+                foreach (CustomAttributeTypedArgument cata in cad.ConstructorArguments)
+                {
+                    Assert.True(cata.Equals(cata));
+                    Assert.True(cata.Equals((object)cata));
+
+                    var notEqualArgument = new CustomAttributeTypedArgument(new [] { new CustomAttributeTypedArgument(0) });
+                    Assert.False(cata.Equals(notEqualArgument));
+                    Assert.False(cata.Equals((object)notEqualArgument));
+
+                    return;
+                }
+            }
+
+            Assert.True(false, "Expected to find MyAttr Attribute");
+        }
+
+        [Fact]
         public static void Test_CustomAttributeTypedArgument_ToString()
         {
             var argument = new CustomAttributeTypedArgument(new [] { new CustomAttributeTypedArgument(0) });
index 3fd806b..1298a7c 100644 (file)
@@ -10,4 +10,7 @@ namespace System.ServiceProcess
     {
         public void Stop(bool stopDependentServices) { }
     }
+    public readonly partial struct SessionChangeDescription : System.IEquatable<System.ServiceProcess.SessionChangeDescription>
+    {
+    }
 }
index 8fd0582..fac46ae 100644 (file)
@@ -17,6 +17,8 @@ System.ServiceProcess.ServiceType</PackageDescription>
     <IsPartialFacadeAssembly Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">true</IsPartialFacadeAssembly>
     <OmitResources Condition="'$(IsPartialFacadeAssembly)' == 'true'">true</OmitResources>
     <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(IsPartialFacadeAssembly)' != 'true' and '$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_ServiceController</GeneratePlatformNotSupportedAssemblyMessage>
+    <!-- we cannot add API on .NETStandard since it would be absent on .NETFramework, suppress warnings that require API changes -->
+    <NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETStandard'">$(NoWarn);CA1066</NoWarn>
   </PropertyGroup>
   <ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' and '$(TargetsWindows)' == 'true'">
     <Compile Include="$(CommonPath)System\Text\ValueStringBuilder.cs"
index bc11eae..e4924e9 100644 (file)
@@ -6,6 +6,9 @@ using System.Diagnostics.CodeAnalysis;
 namespace System.ServiceProcess
 {
     public readonly struct SessionChangeDescription
+#if NETCOREAPP
+        : IEquatable<SessionChangeDescription>
+#endif
     {
         internal SessionChangeDescription(SessionChangeReason reason, int id)
         {
@@ -17,34 +20,20 @@ namespace System.ServiceProcess
 
         public int SessionId { get; }
 
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            if (!(obj is SessionChangeDescription))
-            {
-                return false;
-            }
+        public override int GetHashCode() =>
+            (int)Reason ^ SessionId;
 
-            return Equals((SessionChangeDescription)obj);
-        }
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is SessionChangeDescription other && Equals(other);
 
-        public override int GetHashCode()
-        {
-            return (int)Reason ^ SessionId;
-        }
+        public bool Equals(SessionChangeDescription changeDescription) =>
+            (Reason == changeDescription.Reason) &&
+            (SessionId == changeDescription.SessionId);
 
-        public bool Equals(SessionChangeDescription changeDescription)
-        {
-            return (Reason == changeDescription.Reason) && (SessionId == changeDescription.SessionId);
-        }
+        public static bool operator ==(SessionChangeDescription a, SessionChangeDescription b) =>
+            a.Equals(b);
 
-        public static bool operator ==(SessionChangeDescription a, SessionChangeDescription b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(SessionChangeDescription a, SessionChangeDescription b)
-        {
-            return !a.Equals(b);
-        }
+        public static bool operator !=(SessionChangeDescription a, SessionChangeDescription b) =>
+            !a.Equals(b);
     }
 }
index d6bf03a..e44843b 100644 (file)
@@ -176,8 +176,9 @@ namespace System.Speech.Internal.Synthesis
         void CompleteSkip(int skipped);
         void LoadResource([MarshalAs(UnmanagedType.LPWStr)] string resource, ref string mediaType, out IStream stream);
     }
+
     [StructLayout(LayoutKind.Sequential)]
-    internal struct SpeechEventSapi
+    internal struct SpeechEventSapi : IEquatable<SpeechEventSapi>
     {
         public short EventId;
         public short ParameterType;
@@ -185,27 +186,22 @@ namespace System.Speech.Internal.Synthesis
         public long AudioStreamOffset;
         public IntPtr Param1;   // Always just a numeric type - contains no unmanaged resources so does not need special clean-up.
         public IntPtr Param2;   // Can be a numeric type, or pointer to string or object. Use SafeSapiLParamHandle to cleanup.
-        public static bool operator ==(SpeechEventSapi event1, SpeechEventSapi event2)
-        {
-            return event1.EventId == event2.EventId && event1.ParameterType == event2.ParameterType && event1.StreamNumber == event2.StreamNumber && event1.AudioStreamOffset == event2.AudioStreamOffset && event1.Param1 == event2.Param1 && event1.Param2 == event2.Param2;
-        }
-        public static bool operator !=(SpeechEventSapi event1, SpeechEventSapi event2)
-        {
-            return !(event1 == event2);
-        }
-        public override bool Equals(object obj)
-        {
-            if (!(obj is SpeechEventSapi))
-            {
-                return false;
-            }
 
-            return this == (SpeechEventSapi)obj;
-        }
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
+        public static bool operator ==(SpeechEventSapi event1, SpeechEventSapi event2) => event1.Equals(event2);
+        public static bool operator !=(SpeechEventSapi event1, SpeechEventSapi event2) => !event1.Equals(event2);
+
+        public override bool Equals(object obj) =>
+            obj is SpeechEventSapi other && Equals(other);
+
+        public bool Equals(SpeechEventSapi other) =>
+            EventId == other.EventId &&
+            ParameterType == other.ParameterType &&
+            StreamNumber == other.StreamNumber &&
+            AudioStreamOffset == other.AudioStreamOffset &&
+            Param1 == other.Param1 &&
+            Param2 == other.Param2;
+
+        public override int GetHashCode() => base.GetHashCode();
     }
 
     #endregion
index 66c637e..774ee9e 100644 (file)
@@ -14,7 +14,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Text
 {
-    internal readonly struct Rune
+    internal readonly struct Rune : IEquatable<Rune>
     {
         private const int MaxUtf16CharsPerRune = 2; // supplementary plane code points are encoded as 2 UTF-16 code units
 
index c6754b8..5ba715c 100644 (file)
@@ -5,7 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Text.RegularExpressions.Symbolic
 {
-    internal readonly struct SymbolicMatch
+    internal readonly struct SymbolicMatch : IEquatable<SymbolicMatch>
     {
         /// <summary>Indicates failure to find a match.</summary>
         internal static SymbolicMatch NoMatch => new SymbolicMatch(-1, -1);
@@ -20,17 +20,21 @@ namespace System.Text.RegularExpressions.Symbolic
         }
 
         public int Index { get; }
+
         public int Length { get; }
+
         public bool Success => Index >= 0;
 
         public static bool operator ==(SymbolicMatch left, SymbolicMatch right) =>
-            left.Index == right.Index && left.Length == right.Length;
+            left.Equals(right);
 
         public static bool operator !=(SymbolicMatch left, SymbolicMatch right) =>
-            !(left == right);
+            !left.Equals(right);
 
         public override bool Equals([NotNullWhen(true)] object? obj) =>
-            obj is SymbolicMatch other && this == other;
+            obj is SymbolicMatch other && Equals(other);
+
+        public bool Equals(SymbolicMatch other) => Index == other.Index && Length == other.Length;
 
         public override int GetHashCode() => HashCode.Combine(Index, Length);
     }
index ba522d5..4e60696 100644 (file)
@@ -4,7 +4,7 @@
 namespace System.Text.RegularExpressions.Symbolic
 {
     /// <summary>Misc information of structural properties of a <see cref="SymbolicRegexNode{S}"/> that is computed bottom up.</summary>
-    internal readonly struct SymbolicRegexInfo
+    internal readonly struct SymbolicRegexInfo : IEquatable<SymbolicRegexInfo>
     {
         private const uint IsAlwaysNullableMask = 1;
         private const uint StartsWithLineAnchorMask = 2;
@@ -177,7 +177,9 @@ namespace System.Text.RegularExpressions.Symbolic
                 containsSomeCharacter: info.ContainsSomeCharacter,
                 isLazy: info.IsLazy);
 
-        public override bool Equals(object? obj) => obj is SymbolicRegexInfo i && i._info == _info;
+        public override bool Equals(object? obj) => obj is SymbolicRegexInfo i && Equals(i);
+
+        public bool Equals(SymbolicRegexInfo other) => _info == other._info;
 
         public override int GetHashCode() => _info.GetHashCode();
 
index 1237c49..3c5f126 100644 (file)
@@ -235,7 +235,7 @@ namespace System.Threading
         public static T EnsureInitialized<T>([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, System.Func<T> valueFactory) where T : class { throw null; }
         public static T EnsureInitialized<T>([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func<T> valueFactory) where T : class { throw null; }
     }
-    public partial struct LockCookie
+    public partial struct LockCookie : System.IEquatable<System.Threading.LockCookie>
     {
         private int _dummyPrimitive;
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
index 6a76ceb..a9c9011 100644 (file)
@@ -9,40 +9,27 @@ namespace System.Threading
     /// Stores the lock state of a <see cref="ReaderWriterLock"/> before its lock state is changed, such that the lock state may
     /// later be restored.
     /// </summary>
-    public struct LockCookie
+    public struct LockCookie : IEquatable<LockCookie>
     {
         internal LockCookieFlags _flags;
         internal ushort _readerLevel;
         internal ushort _writerLevel;
         internal int _threadID;
 
-        public override int GetHashCode()
-        {
-            return (int)_flags + _readerLevel + _writerLevel + _threadID;
-        }
+        public override int GetHashCode() =>
+            (int)_flags + _readerLevel + _writerLevel + _threadID;
 
-        public override bool Equals([NotNullWhen(true)] object? obj)
-        {
-            return obj is LockCookie && Equals((LockCookie)obj);
-        }
+        public override bool Equals([NotNullWhen(true)] object? obj) =>
+            obj is LockCookie other && Equals(other);
 
-        public bool Equals(LockCookie obj)
-        {
-            return
-                _flags == obj._flags &&
-                _readerLevel == obj._readerLevel &&
-                _writerLevel == obj._writerLevel &&
-                _threadID == obj._threadID;
-        }
+        public bool Equals(LockCookie obj) =>
+            _flags == obj._flags &&
+            _readerLevel == obj._readerLevel &&
+            _writerLevel == obj._writerLevel &&
+            _threadID == obj._threadID;
 
-        public static bool operator ==(LockCookie a, LockCookie b)
-        {
-            return a.Equals(b);
-        }
+        public static bool operator ==(LockCookie a, LockCookie b) => a.Equals(b);
 
-        public static bool operator !=(LockCookie a, LockCookie b)
-        {
-            return !(a == b);
-        }
+        public static bool operator !=(LockCookie a, LockCookie b) => !a.Equals(b);
     }
 }
index 9180438..f52ae1f 100644 (file)
@@ -202,12 +202,13 @@ namespace System.Transactions
         public TransactionManagerCommunicationException(string? message) { }
         public TransactionManagerCommunicationException(string? message, System.Exception? innerException) { }
     }
-    public partial struct TransactionOptions
+    public partial struct TransactionOptions : System.IEquatable<System.Transactions.TransactionOptions>
     {
-        private int _dummyPrimitive;
+        private readonly int _dummyPrimitive;
         public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } set { } }
         public System.TimeSpan Timeout { get { throw null; } set { } }
         public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
+        public bool Equals(System.Transactions.TransactionOptions other) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; }
         public static bool operator !=(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; }
index 1fa3428..4ce7bb4 100644 (file)
@@ -5,7 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace System.Transactions
 {
-    public struct TransactionOptions
+    public struct TransactionOptions : IEquatable<TransactionOptions>
     {
         private TimeSpan _timeout;
         private IsolationLevel _isolationLevel;
@@ -26,7 +26,10 @@ namespace System.Transactions
 
         public override bool Equals([NotNullWhen(true)] object? obj) => obj is TransactionOptions transactionOptions && Equals(transactionOptions);
 
-        private bool Equals(TransactionOptions other) =>
+        /// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
+        /// <param name="other">An instance to compare with this instance.</param>
+        /// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
+        public bool Equals(TransactionOptions other) =>
             _timeout == other._timeout &&
             _isolationLevel == other._isolationLevel;
 
index c62dde6..90b6123 100644 (file)
@@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
 
 namespace Mono
 {
-    internal unsafe struct RuntimeClassHandle
+    internal unsafe struct RuntimeClassHandle : IEquatable<RuntimeClassHandle>
     {
         private readonly RuntimeStructs.MonoClass* value;
 
@@ -125,7 +125,7 @@ namespace Mono
         }
     }
 
-    internal struct RuntimeEventHandle
+    internal struct RuntimeEventHandle : IEquatable<RuntimeEventHandle>
     {
         private readonly IntPtr value;
 
@@ -165,7 +165,7 @@ namespace Mono
         }
     }
 
-    internal struct RuntimePropertyHandle
+    internal struct RuntimePropertyHandle : IEquatable<RuntimePropertyHandle>
     {
         private readonly IntPtr value;
 
index 9f73b99..c30bf25 100644 (file)
@@ -6,7 +6,7 @@ using System.Reflection;
 
 namespace System
 {
-    public struct ModuleHandle
+    public struct ModuleHandle : IEquatable<ModuleHandle>
     {
         private readonly IntPtr value;
 
index 23f7668..c120455 100644 (file)
@@ -1,6 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals
+
 namespace System
 {
     public partial struct Nullable<T>
index af1cead..9b9c5a4 100644 (file)
@@ -14,7 +14,7 @@ using Newtonsoft.Json.Linq;
 
 namespace Microsoft.WebAssembly.Diagnostics
 {
-    public struct SessionId
+    public struct SessionId : IEquatable<SessionId>
     {
         public readonly string sessionId;
 
@@ -26,7 +26,9 @@ namespace Microsoft.WebAssembly.Diagnostics
         // hashset treats 0 as unset
         public override int GetHashCode() => sessionId?.GetHashCode() ?? -1;
 
-        public override bool Equals(object obj) => (obj is SessionId) ? ((SessionId)obj).sessionId == sessionId : false;
+        public override bool Equals(object obj) => obj is SessionId other && Equals(other);
+
+        public bool Equals(SessionId other) => other.sessionId == sessionId;
 
         public static bool operator ==(SessionId a, SessionId b) => a.sessionId == b.sessionId;
 
@@ -37,7 +39,7 @@ namespace Microsoft.WebAssembly.Diagnostics
         public override string ToString() => $"session-{sessionId}";
     }
 
-    public struct MessageId
+    public struct MessageId : IEquatable<MessageId>
     {
         public readonly string sessionId;
         public readonly int id;
@@ -54,7 +56,9 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         public override int GetHashCode() => (sessionId?.GetHashCode() ?? 0) ^ id.GetHashCode();
 
-        public override bool Equals(object obj) => (obj is MessageId) ? ((MessageId)obj).sessionId == sessionId && ((MessageId)obj).id == id : false;
+        public override bool Equals(object obj) => obj is MessageId other && Equals(other);
+
+        public bool Equals(MessageId other) => other.sessionId == sessionId && other.id == id;
     }
 
     internal class DotnetObjectId
index 9526a60..34b42e2 100644 (file)
@@ -478,7 +478,9 @@ public class PInvokeTableGenerator : Task
     private static void Error (string msg) => throw new LogAsErrorException(msg);
 }
 
+#pragma warning disable CA1067
 internal sealed class PInvoke : IEquatable<PInvoke>
+#pragma warning restore CA1067
 {
     public PInvoke(string entryPoint, string module, MethodInfo method)
     {