当装箱类型未知时,检查不同类型的盒装值类型的相等性
本文关键字:类型 盒装 同类型 检查 未知 | 更新日期: 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 相等?
更新
伊万斯托耶夫在评论中建议我尝试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
方法调用相比,额外的检查、分支、框和取消框。