== 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[]
