107 lines
4.4 KiB
Plaintext
107 lines
4.4 KiB
Plaintext
== Why is this an issue?
|
|
|
|
In C#, the https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals[`Object.ReferenceEquals`] method is used to compare two https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types[reference type] variables. If you use this method to compare two https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types[value types], such as `int`, `float`, or `bool` you will not get the expected results because value type variables contain an instance of the type and not a reference to it.
|
|
|
|
Due to value type variables containing directly an instance of the type, they can't have the same reference, and using `Object.ReferenceEquals` to compare them will always return `false` even if the compared variables have the same value.
|
|
|
|
== How to fix it
|
|
|
|
When comparing value types, prefer using the https://learn.microsoft.com/en-us/dotnet/api/system.object.equals[`Object.Equals`].
|
|
|
|
Note that in the case of https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct[structure types], it is recommended to https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type#struct-example[implement value equality]. If not, S3898 might raise.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
using System;
|
|
|
|
struct MyStruct
|
|
{
|
|
int valueA;
|
|
int valueB;
|
|
}
|
|
|
|
static class MyClass
|
|
{
|
|
public static void Method(MyStruct struct1, MyStruct struct2)
|
|
{
|
|
if (Object.ReferenceEquals(struct1, struct2)) // Noncompliant: this will be always false
|
|
{
|
|
// ...
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
using System;
|
|
|
|
struct MyStruct : IEquatable<MyStruct>
|
|
{
|
|
int valueA;
|
|
int valueB;
|
|
|
|
public bool Equals(MyStruct other) => valueA == other.valueA && valueB == other.valueB;
|
|
|
|
public override bool Equals(object obj) => obj is MyStruct other && Equals(other);
|
|
|
|
public override int GetHashCode() => HashCode.Combine(valueA, valueB);
|
|
|
|
public static bool operator ==(MyStruct lhs, MyStruct rhs) => lhs.Equals(rhs);
|
|
|
|
public static bool operator !=(MyStruct lhs, MyStruct rhs) => !(lhs == rhs);
|
|
}
|
|
|
|
static class MyClass
|
|
{
|
|
public static void Method(MyStruct struct1, MyStruct struct2)
|
|
{
|
|
if (struct1.Equals(struct2)) // Compliant: value are compared
|
|
{
|
|
// ...
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals[`Object.ReferenceEquals(Object, Object)` Method]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.object.equals[`Object.Equals` Method]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types[Value types (C# reference)]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types[Reference types (C# reference)]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators[Equality operators - test if two objects are equal or not]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type#struct-example[How to define value equality for a class or struct (C# Programming Guide)]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct[Structure types (C# reference)]
|
|
* S3898 - Value types should implement "IEquatable<T>"
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Use a different kind of comparison for these value types.
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 3 Jun 2015, 15:56:16 Ann Campbell wrote:
|
|
\[~tamas.vajk] I'm a little confused about whether it should be `Object...` or `object...`. I followed your lead, but am a little uncomfortable about the inconsistency in usage between title and code sample
|
|
|
|
=== on 8 Jun 2015, 09:32:21 Tamas Vajk wrote:
|
|
LGTM, I've changed the `object` to `Object` just to conform to the title, but there is no difference, because `object` is just an alias for `System.Object`
|
|
|
|
endif::env-github,rspecator-view[]
|