为什么操作符的静态重载可以调用同一类的虚方法?
本文关键字:一类 方法 静态 操作符 重载 调用 为什么 | 更新日期: 2023-09-27 18:03:27
我正在探索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。=覆盖
type1 == type2 => True
虽然我完全意识到通过这种方式重写相等操作符可能会出现的意外,但我想知道的是为什么有可能最终从静态方法调用实例虚拟方法(MyType类中的受保护bool Equals(MyType other))。
在
操作符
关键字,但据我所知,它在IL中被翻译为静态方法:
.method public hidebysig specialname static bool op_Equality(class MyType lhs, class MyType rhs) cil managed
我怀疑魔法发生在物体的某个地方。等于静态方法调用,但我不知道它是如何工作的。能告诉我吗?
不需要任何魔法。Equals
方法在object
上是虚拟的,并且您正在重写它-因此当调用((object)lhs).Equals
时,当然会调用您的重写方法。这就是你正在调用的静态object.Equals
:)如果你在其他任何地方调用Equals
,也会发生同样的事情,操作符真的只是静态方法。
没有什么神奇的——你自己也可以实现类似的代码。您使用的Object.Equal(object,object)
最终调用left.Equals(right)
产生的结果如下:
如果两个对象不代表相同的对象引用,并且都不为空,则调用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
}
这是因为当访问类本身(以及它的派生类)内部的静态成员(字段/方法等)时,可以省略类型标识符。
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.Equals
,省略Object.
。