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

本文关键字:类型 盒装 同类型 检查 未知 | 更新日期: 2023-09-27 18:31:57

我正在比较 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

它返回假。 起初,它似乎正在进行参考检查,因为短篇被装箱在一个对象中。 但是,当我将未装箱的短裤与盒装短裤进行比较时,它返回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()

那么,在框架中究竟发生了什么,即盒装短裤和未装箱短裤相等,盒装短裤和未装箱 int

不相等,但未装箱短裤和未装箱 int 相等?

更新

伊万斯托耶夫在评论中建议我尝试Convert.ToInt32(). 虽然比我拆箱慢 3.47 倍,如果类型已知((int)(short)BoxedShort),这显然不是一个选项,但它仍然比 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

我会等一会儿,看看是否有其他答案。

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

一切都有一个合乎逻辑的解释。

首先,当将"

收件箱"(即类型化)值与不同类型的"未装箱"值进行比较时,编译器会考虑定义的implicit转换,并最终扩大其中一个值,然后使用相应的==运算符。

当您有一个装箱值并使用 Equals 方法时,情况会有所不同,因为Equals实现通常只检查相同的类型,而不会执行。以下是从参考源获取的Int32的实现:

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

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

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

但是,与其Convert.ChangeType不如像这样使用 Convert.ToInt32

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

之所以这样更快Convert.ChangeType是因为首先需要使用类型检查并实际调用一个具体的ToXXX方法。其次,由于Convert.ChangeType的返回类型是object,因此该值被装箱。最后,您需要将其拆箱回int(现在知道它会成功)。换句话说,与基本上调用IConvertible.ToXXX实现的直接ToXXX方法调用相比,额外的检查、分支、框和取消框。