我在读完这篇文章之后来到这里并且没有找到相关的答案 - 所以在你阅读整个问题之前,请不要将其标记为副本.
我一直在使用反射器并进行调查.Object.Equals我看到的是:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
Run Code Online (Sandbox Code Playgroud)
而且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);
Run Code Online (Sandbox Code Playgroud)
现在我看不到实现RuntimeHelpers.Equals但是通过描述,如果两个对象不是同一个实例并且不是null,它将object.Equals再次调用该方法,我将进入一个循环(我说的是纯对象).
当我说纯物体时我的意思是这样的:
object pureObj1 = new object();
object pureObj2 = new object();
bool areEql = pureObj1.Equals(pureObj2);
Run Code Online (Sandbox Code Playgroud)
通过文档,这应该调用Object.Equals并获得一个重复的stackoverflow.我想也许文档是错误的,这会检查基本对象的引用相等性 - 但我想确定.
结论:
当通过Equals调用比较两个纯对象(例如,不将字符串转换为对象)时- 它如何确定它们是否相等?- 如果我不覆盖Equals方法并且调用Equals两个对象会发生什么?
无论如何,Ps在那里我可以看到RuntimeHelpers.Equals源代码?
Jud*_*con 10
MSDN的页面object.Equals(object)详细介绍了这一点.具体而言,引用类型的默认实现是引用相等."继承人备注"部分中的表格是最直接的.
参考平等; 相当于调用Object.ReferenceEquals.
MSDN的页面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;
}
}
Run Code Online (Sandbox Code Playgroud)
打印下面的输出:
假
假
Bar.Equals()调用
假
假
Baz.Equals()调用
假
假
Qux.Equals()调用
真正
假
所以我从Hans Passant给出的答案中Math.Pow()略微说道 ......
这是\ CLR\SRC \虚拟机\在ecall.cpp相关的代码SSCLI2.0
FCFuncStart(gObjectFuncs)
FCIntrinsic("GetType", ObjectNative::GetClass, CORINFO_INTRINSIC_Object_GetType)
FCFuncElement("InternalGetHashCode", ObjectNative::GetHashCode)
FCFuncElement("InternalEquals", ObjectNative::Equals)
FCFuncElement("MemberwiseClone", ObjectNative::Clone)
FCFuncEnd()
Run Code Online (Sandbox Code Playgroud)
这是它映射到的\ 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
Run Code Online (Sandbox Code Playgroud)
我看到参考比较,空检查,值类型排除,类型匹配检查和按位相等比较.我看不出怎么Object.Equals(Object)称呼.我认为文档RuntimeHelpers.Equals(object,object)是完全错误的.
Object.Equals是虚拟的.类型覆盖它以具有不同的行为.
正如您所注意到的,默认实现调用MethodImplOptions.InternalCall方法(即,它是.NET运行时内部的一部分).此方法通过直接查看引用来执行引用相等(实际上它执行C/C++指针比较).
没有递归.
NB.文档ReferenceHelper.Equals说:
真如果O1参数是相同的实例作为O2参数,或者如果两者都为空,或者如果
o1.Equals(o2)返回真; 否则,错误.
(来源强调.)
但是这意味着a.Equals(b)哪里Object.ReferenceEquals(a, b)是假的,两者都不是null,那就Object.Equals(object)叫来ReferenceHelper.Equals(object, object)电话Object.Equals(object)...... 这似乎是一个文档错误(对于不覆盖的类型,运行时行为不是递归的Equals(object),然后调用不同的对象导致false引用相等的结果).
| 归档时间: |
|
| 查看次数: |
1012 次 |
| 最近记录: |