结构包装类型C#

时间:2018-07-11 15:57:35

标签: c# struct value-type

C#参考说明了对于值类型:

  

ValueType.Equals(Object)方法将覆盖Object.Equals(Object)   并提供所有值均等的默认实现   .NET Framework中的值类型。

     

如果当前实例和obj的任何字段均未引用   类型,Equals方法将对两个字节进行逐字节比较   内存中的对象。否则,它会使用反射来比较   obj和此实例的对应字段。

https://msdn.microsoft.com/en-us/library/2dts52z7(v=vs.110).aspx

这样,因为int是一个值类型,所以我希望一个简单的int包装器将等于它包装的int,因为在逐字节比较中它是相同的-它们都只包含一个int :

    public struct Id
    {
        public Id(int id)
        {
            Id = id;
        }
        public int Id { get; }
    }

    Console.WriteLine(new Id(17).Equals(17);

但是它实际上打印为false。为什么会这样?

3 个答案:

答案 0 :(得分:3)

这些不是同一类型。尽管文本没有明确说明,但Equals方法checks属于同一类型。

这将起作用:

new Id(17).Equals(new Id(17));

如果要处理结构上两种不同类型的比较,则需要覆盖Equals并自己处理。

答案 1 :(得分:2)

relevant source是:

public abstract class ValueType {
    [System.Security.SecuritySafeCritical]
    public override bool Equals (Object obj) {
        BCLDebug.Perf(false, "ValueType::Equals is not fast.  "+this.GetType().FullName+" should override Equals(Object)");
        if (null==obj) {
            return false;
        }
        RuntimeType thisType = (RuntimeType)this.GetType();
        RuntimeType thatType = (RuntimeType)obj.GetType();

        if (thatType!=thisType) {
            return false;
        }

        Object thisObj = (Object)this;
        Object thisResult, thatResult;

        // if there are no GC references in this object we can avoid reflection 
        // and do a fast memcmp
        if (CanCompareBits(this))
            return FastEqualsCheck(thisObj, obj);

        FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        for (int i=0; i<thisFields.Length; i++) {
            thisResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(thisObj);
            thatResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(obj);

            if (thisResult == null) {
                if (thatResult != null)
                    return false;
            }
            else
            if (!thisResult.Equals(thatResult)) {
                return false;
            }
        }

        return true;
    }

如您所见,它在检查字节之前先验证参数的类型是否匹配。由于您的类型不是int,因此它将始终返回false。

答案 2 :(得分:0)

通常,即使两个对象都封装相同的值,对象的Equals方法也不会认为它等于任何其他类型的对象。

由于重载,将某些类型的值传递给其他类型的Equals方法的行为可能导致它们转换为与原始类型相同的类型。例如,(16777216.0f).Equals(16777217)将选择重载Equals(float),将int16777217转换为最接近的float值(即16777216.0f),依次比较等于16777216.0f。如将object((object)16777.216.0f).Equals(16777216)中的任何一个操作数转换为(16777.216.0f).Equals((object)16777216),可以防止此行为,其中任何一个都将报告float对象与{{1} }对象(即使它们具有相同的数值)。