0

我在 C# 中探索平等,我正在沿着这条线实现一些东西:

public class MyType
{
    public string MyProperty { get; set; }

    public MyType(string myProperty)
    {
        MyProperty = myProperty;
    }

    protected bool Equals(MyType other)
    {
        Console.WriteLine("I'm calling the MyType.Equals override");
        return MyProperty == other.MyProperty;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((MyType) obj);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException();
    }

    public static bool operator ==(MyType lhs, MyType rhs)
    {
        return Equals(lhs, rhs);
    }

    public static bool operator !=(MyType lhs, MyType rhs)
    {
        return !(lhs == rhs);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var type1 = new MyType("test");
        var type2 = new MyType("test");

        Console.WriteLine($"type1 == type2 => {type1 == type2}");
        Console.Read();
    }
}

输出是

我正在调用 MyType.Equals 覆盖
type1 == type2 => True

虽然我完全意识到以这种方式覆盖相等运算符可能会出现的意外,但我想知道的是为什么最终有可能在 MyType 中调用实例虚拟方法(protected bool Equals(MyType other)类)来自静态方法。
好的,鉴于

操作员

关键字,但据我所知,它在 IL 中被翻译为静态方法:

.method public hidebysig specialname static bool  op_Equality(class MyType lhs, class MyType rhs) cil managed

我怀疑魔法发生在 object.Equals 静态方法调用的某个地方,但我不知道它实际上是如何工作的。想了解一下吗?

4

3 回答 3

1

不需要任何魔法。该Equals方法是 virtual onobject并且您正在覆盖它 - 所以在调用 时((object)lhs).Equals,当然会调用您的覆盖方法。这就是object.Equals你调用的静态函数的作用:) 如果你在其他任何地方调用也会发生同样的事情Equals,操作符实际上只是静态方法。

于 2016-08-23T06:17:52.787 回答
1

没有魔法 - 你可以自己实现类似的代码就好了。 Object.Equal(object,object)您最终使用的调用会left.Equals(right)产生您看到的结果:

如果这两个对象不代表同一个对象引用且都不为 null,则调用 objA.Equals(objB) 并返回结果。这意味着如果 objA 覆盖 Object.Equals(Object) 方法,则调用此覆盖。

public static bool operator ==(MyType lhs, MyType rhs)
{
    return Equals(lhs, rhs); // calls Object.Equal(object,object)
}

该代码大致相当于以下内联实现:

public static bool operator ==(MyType lhs, MyType rhs)
{
    if (lhs == null || lhs == null) 
    {
        // this branch is not executed in your sample
        return RefrenceEquals(lhs,rhs);
    } 
    return lhs.Equal(rhs); // calls override bool Equals(object obj)
    // which in turn calls 
    // bool Equals(MyType other) since both are other is not null
}
于 2016-08-23T06:11:06.970 回答
1

这是因为在访问类本身(及其派生类)内部的静态成员(字段/方法/等)时,可以省略类型标识符。

class A
{
    public static int Number = 0;

    protected static void MA()
    {
        var n = Number;    // var n = A.Number;
    }
}

在派生类中:

class B : A
{
    public static void MB()
    {
        var n = Number;   // var n = A.Number;
        MA();             // A.MA();
    }
}

由于每个类都派生自,因此可以从每个类访问System.Object公共静态方法,而无需省略。Object.EqualsObject.

于 2016-08-23T06:52:27.420 回答