看完我就到了this我没有找到相关答案 - 所以请在阅读整个问题之前不要将其标记为重复。
我一直在使用反射器并查看 Object.Equals
。我看到的是:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
RuntimeHelpers.Equals
看起来像这样:
// System.Runtime.CompilerServices.RuntimeHelpers
/// <summary>Determines whether the specified <see cref="T:System.Object" /> instances are considered equal.</summary>
/// <returns>true if the <paramref name="o1" /> parameter is the same instance as the <paramref name="o2" /> parameter, or if both are null, or if o1.Equals(o2) returns true; otherwise, false.</returns>
/// <param name="o1">The first object to compare. </param>
/// <param name="o2">The second object to compare. </param>
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
public new static extern bool Equals(object o1, object o2);
现在我看不到 RuntimeHelpers.Equals
的实现,但是根据描述,如果两个对象不是同一个实例并且不为空,它将调用 对象。再次使用 Equals
方法,我会进入一个循环(我说的是纯对象)。
当我说纯对象时,我的意思是这样的:
object pureObj1 = new object();
object pureObj2 = new object();
bool areEql = pureObj1.Equals(pureObj2);
根据文档,这应该调用 Object.Equals
并获得一个recusive stackoverflow。我想也许文档是错误的,这会检查基本对象的引用相等性 - 但我想确定。
底线:
通过 Equals
调用比较两个纯对象(例如,不将字符串转换为对象)时 - 它如何确定它们是否相等? - 如果我不覆盖 Equals
方法并在两个对象上调用 Equals
会发生什么情况?
附言无论如何,我可以看到 RuntimeHelpers.Equals
源代码吗?
最佳答案
MSDN's page on object.Equals(object)
详细介绍了这一点。具体来说,引用类型的默认实现是引用相等性。 “继承者须知”部分的表格是最直接的。
Reference equality; equivalent to calling Object.ReferenceEquals.
MSDN's page on RuntimeHelpers.Equals(object,object)
确实说 Object.Equals(Object)
在其参数引用不相等且两者都不为 null 的情况下被调用。这显然是错误的;实际表现出的行为是 RuntimeHelpers.Equals(object,object)
从不调用 Object.Equals(Object)
。
例如,这个 LINQPad 脚本:
void Main()
{
object left = new Foo();
object right = new Foo();
left.Equals(right).Dump();
RuntimeHelpers.Equals( left, right ).Dump();
left = new Bar();
right = new Bar();
left.Equals(right).Dump();
RuntimeHelpers.Equals( left, right ).Dump();
left = new Baz();
right = new Baz();
left.Equals(right).Dump();
RuntimeHelpers.Equals( left, right ).Dump();
left = new Qux();
right = new Qux();
left.Equals(right).Dump();
RuntimeHelpers.Equals( left, right ).Dump();
}
private class Foo {}
private class Bar {
public override bool Equals(object obj) {
"Bar.Equals() called".Dump();
return base.Equals(obj);
}
}
private class Baz {
public override bool Equals(object obj) {
"Baz.Equals() called".Dump();
return RuntimeHelpers.Equals( this, obj );
}
}
private class Qux {
public override bool Equals(object obj) {
"Qux.Equals() called".Dump();
return true;
}
}
打印下面的输出:
False
False
Bar.Equals() called
False
False
Baz.Equals() called
False
False
Qux.Equals() called
True
False
所以我抄袭了一点 an answer Hans Passant gave about Math.Pow()
...
这是SSCLI2.0中\clr\src\vm\ecall.cpp中的相关代码
FCFuncStart(gObjectFuncs)
FCIntrinsic("GetType", ObjectNative::GetClass, CORINFO_INTRINSIC_Object_GetType)
FCFuncElement("InternalGetHashCode", ObjectNative::GetHashCode)
FCFuncElement("InternalEquals", ObjectNative::Equals)
FCFuncElement("MemberwiseClone", ObjectNative::Clone)
FCFuncEnd()
这是它映射到的\clr\src\vm\comobject.cpp 中函数的代码:
FCIMPL2(FC_BOOL_RET, ObjectNative::Equals, Object *pThisRef, Object *pCompareRef)
{
CONTRACTL
{
THROWS;
DISABLED(GC_NOTRIGGER);
INJECT_FAULT(FCThrow(kOutOfMemoryException););
MODE_COOPERATIVE;
SO_TOLERANT;
}
CONTRACTL_END;
if (pThisRef == pCompareRef)
FC_RETURN_BOOL(TRUE);
// Since we are in FCALL, we must handle NULL specially.
if (pThisRef == NULL || pCompareRef == NULL)
FC_RETURN_BOOL(FALSE);
MethodTable *pThisMT = pThisRef->GetMethodTable();
// If it's not a value class, don't compare by value
if (!pThisMT->IsValueClass())
FC_RETURN_BOOL(FALSE);
// Make sure they are the same type.
if (pThisMT != pCompareRef->GetMethodTable())
FC_RETURN_BOOL(FALSE);
// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
(void *) (pThisRef+1),
(void *) (pCompareRef+1),
pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0;
FC_GC_POLL_RET();
FC_RETURN_BOOL(ret);
}
FCIMPLEND
我看到了引用比较、空检查、值类型排除、类型匹配检查和按位相等比较。我看不到 Object.Equals(Object)
是如何调用的。我认为 RuntimeHelpers.Equals(object,object)
的文档完全不正确。
关于c# - 对象等于 - 不覆盖等于的纯对象或引用类型的基本逻辑是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26977431/