对象相等-不覆盖相等的纯对象或引用类型的基本逻辑是什么?

阿米尔·波波维奇(Amir Popovich)

阅读完这篇文章后我来到了这里,但没有找到相关的答案-因此,在您阅读完整个问题之前,请不要将其标记为重复。

我一直在使用反射器,看着。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但通过描述,如果两个对象都不是同一实例且不为null,它将object.Equals再次调用该方法,并且我将陷入循环(我在谈论纯对象))。

当我说纯净的对象时,我的意思是这样的:

object pureObj1 = new object();
object pureObj2 = new object();
bool areEql = pureObj1.Equals(pureObj2);

通过文档,这应该调用Object.Equals并获得可追溯的stackoverflow我想也许文档是错误的,并且这检查了基本对象的引用相等性,但是我想确定一下。

底线:
通过Equals调用比较两个纯对象(例如,不将字符串转换为对象)时,如何确定它们是否相等?-如果不重写Equals方法而调用Equals两个对象,会发生什么?
ps有反正我可以看到RuntimeHelpers.Equals源代码吗?

裘德·梅兰康(Jude Melancon)

MSDN上的页面object.Equals(object)对此进行了详细介绍。具体来说,引用类型的默认实现是引用相等。“继承者注意事项”部分中的表是最直接的。

参考相等;等效于调用Object.ReferenceEquals。

如果MSDN的RuntimeHelpers.Equals(object,object)Object.Equals(Object)参数引用不相等且都不为null 则会调用MSDN的页面这显然是错误的。实际表现出的行为是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;
    }
}

在下面显示输出:

错误的

错误的

调用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()

这是映射到\ 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)根本不正确。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

对象相等

来自分类Dev

对象和原始类型相等

来自分类Dev

对象和原始类型相等

来自分类Dev

结构对象的相等

来自分类Dev

Java中的相等对象

来自分类Dev

结构对象的相等

来自分类Dev

具有相等对象对生成相等对象列表

来自分类Dev

设置包含和对象相等

来自分类Dev

在HashSet中包含相等的对象

来自分类Dev

设置彼此相等的对象(java)

来自分类Dev

打字稿中的对象相等

来自分类Dev

断言特征对象的相等性?

来自分类Dev

为什么这些对象不相等?

来自分类Dev

为什么对象引用相等没有明显快于字符串相等?

来自分类Dev

assertEqual不打印不相等的对象

来自分类Dev

如何测试特征对象之间的相等性?

来自分类Dev

使用Mockery的“ with”期望测试对象相等性

来自分类Dev

相等对象未被Stream.distinct()过滤

来自分类Dev

比较指针对象的相等性

来自分类Dev

比较shared_ptr对象的相等性

来自分类Dev

更改已设置为相等的对象

来自分类Dev

如何确定JavaScript对象的值相等?

来自分类Dev

比较通过id相等的对象的属性

来自分类Dev

容器对象标识的相等而不是元素明智

来自分类Dev

断言两个sklearn对象相等

来自分类Dev

任意排序对象Kotlin列表的相等性

来自分类Dev

在Java中检查对象相等性而不包含相等性

来自分类Dev

使用==检查对象引用是否相等(在Java中)

来自分类Dev

即使它们相等,NSSet 也不包含该对象