-1

Following (incorrect/dangerous) code

class EvilClass
{
    protected int x;

    public EvilClass(int x)
    {
        this.x = x;
    }

    public override bool Equals(Object obj)
    {
        if ((obj == null) || !this.GetType().Equals(obj.GetType()))
        {
            return false;
        }
        else
        {
            EvilClass p = (EvilClass)obj;
            p.x = 42;
            return (x == p.x);
        }
    }

    public override int GetHashCode()
    {
        return (x << 2);
    }

    public override string ToString()
    {
        return String.Format("EvilClass({0})", x);
    }
}

void Main()
{
    var e1 = new EvilClass(1);
    var e2 = new EvilClass(2);

    var equals = e1.Equals(e2);
    Console.WriteLine("{0}", e1.ToString());
    Console.WriteLine("{0}", e2.ToString());
}

Output:

EvilClass(1)
EvilClass(42)

As you can see, call of e1.Equals(e2) modify e2. If we mark parameter as in compiler would not allow us to modify it.

Object.Equals() not suppose to change it's parameter - so why parameter is not in (input) parameter?

Dmitriy
  • 3,305
  • 7
  • 44
  • 55
  • The `in` keyword in this context was added recently as an optimization for passing value types. Structs in practice. Knowing that a struct that's passed by reference does not get mutated, so the side effect doesn't have to be passed back to the caller, can make code more efficient. It did not make C# a better language. The author of Object.Equals() used the better language, did not need help figuring out what ref/out does. – Hans Passant Jan 31 '19 at 23:17

1 Answers1

6

The most obvious reason is that in was introduced in C# 7.2, while object.Equals has been around since the very first version of .net.

The other reason is that it wouldn't actually change anything. in prevents from mutating the reference, not the actual object. If you try this:

public bool Equals2(in Object obj)
{
    if ((obj == null) || !this.GetType().Equals(obj.GetType()))
    {
        return false;
    }
    else
    {
        EvilClass p = (EvilClass)obj;
        p.x = 42;
        return (x == p.x);
    }
}

Then the output will still be:

EvilClass(1)
EvilClass(42)
Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94