当盒装类型未知时,检查不同类型的盒装值类型的相等性

时间:2016-01-25 13:16:24

标签: c# equality value-type boxing

我将int与运行时未知的盒装数字类型进行比较。此代码对具有相同值的不同类型的未装箱值进行成功的值比较:

short UnboxedShort = short.MaxValue;
object BoxedShort = short.MaxValue; //this boxed type is unknown at runtime
int UnboxedInt = short.MaxValue;

Console.WriteLine(UnboxedInt == UnboxedShort); //returns true
Console.WriteLine(UnboxedInt.Equals(UnboxedShort)); //returns true

此代码无法编译,因为我在值类型和对象上使用了相等运算符:

Console.WriteLine(UnboxedInt == BoxedShort); //doesn't compile

所以,如果我这样做,似乎它会起作用,因为我正在调用基础.Equals()方法:

Console.WriteLine(UnboxedInt.Equals(BoxedShort)); //returns false

返回false。起初,它似乎正在进行参考检查,因为短片被装在一个物体内。但是,当我将未装箱的短片与盒装短片进行比较时,它会返回true

Console.WriteLine(object.Equals(BoxedShort, UnboxedShort)); //returns true

如果类型未知,我可以让比较工作的唯一方法是使用Convert.ChangeType()

Console.WriteLine(UnboxedInt == (int)Convert.ChangeType(BoxedShort, typeof(int))); //returns true
Console.WriteLine(object.Equals(UnboxedInt, Convert.ChangeType(BoxedShort, typeof(int)))); //returns true

这不是首选方法,因为Convert.ChangeType()根据我过去运行的测试而变慢。由于我将在迭代中进行此比较,因此我想避免使用Convert.ChangeType()

那么,在一个盒装的short和unboxed short相等的框架中,究竟是什么呢?盒装的short和unboxed int不相等,但是一个未装箱的short和unboxed int是相等的?

更新

IvanStoev在评论中建议我尝试Convert.ToInt32()。虽然类型已知((int)(short)BoxedShort),但如果我已取消装箱的速度慢了3.47倍,这显然不是一个选项,它仍然比Convert.ChangeType()快4.17倍。

Explicit unbox (175.8 ms)
Convert.ToInt32 (611.6 ms)
Convert.ChangeType (2555 ms)

At 50,000,000 iterations, Convert.ToInt32 is...
   435.80 ms (347.90%) slower than Explicit unbox
    Lose 1 second over 114,731,528 iterations
  1943.40 ms (417.76%) faster than Convert.ChangeType
    Gain 1 second over 25,728,105 iterations

我等一下,看看是否还有其他答案。

1 个答案:

答案 0 :(得分:1)

一切都有合理的解释。

首先,比较"收件箱" (即打字)值为"未装箱的"如果是不同类型的值,编译器会考虑定义的implicit转换,并最终扩展其中一个值,然后使用相应的==运算符。

当你有一个盒装值并使用Equals方法时,情况就不同了,因为Equals实现通常只检查相同的类型而不是性能。以下是从reference source获取Int32的实现:

public override bool Equals(Object obj) {
    if (!(obj is Int32)) {
        return false;
    }
    return m_value == ((Int32)obj).m_value;
}

其他实现类似。我想你现在看到为什么盒装int不等于带有相同值的盒装short,反之亦然。

由于没有简单的方法可以在不知道类型的情况下拆箱值,您应该真正使用转换。所有原始类型都实现IConvertible,允许将盒装值转换为所需类型(如果可能)。

但是,您应该真正使用Convert.ToInt32而不是Convert.ChangeType

bool test = UnboxedInt == Convert.ToInt32(BoxedShort);

这更快的原因是因为Convert.ChangeType首先需要使用类型检查并实际调用其中一个具体的ToXXX方法。其次,由于Convert.ChangeType的返回类型为object,因此该值将被加框。最后你需要将它取消装回int(现在知道它会成功)。换句话说,与直接调用ToXXX实现的直接IConvertible.ToXXX方法调用相比,其他支票,分支,框和展开框。