例如: .method private hidebysig instance void Insert(!TKey key, !TValue 'value', bool add) cil managed{ .maxstack 3 .locals init ( [0] int32 num, [1] int32 num2, [2] int32 num3, [3] int32 num4) L_0000: ldarg.1 L_0001: box !TKey L_0006:
.method private hidebysig instance void Insert(!TKey key, !TValue 'value', bool add) cil managed { .maxstack 3 .locals init ( [0] int32 num, [1] int32 num2, [2] int32 num3, [3] int32 num4) L_0000: ldarg.1 L_0001: box !TKey L_0006: brtrue.s L_000e L_0008: ldc.i4.5 L_0009: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
这是来自Dictionary< int,Object>的内部Add方法.在.NET 4.0中.尽管泛型被广泛吹捧为有助于避免值类型的装箱,但为什么这个系统组件对值类型键的每个操作都进行了低效的检查?如果我理解正确,这不仅会伤害性能,而且总会返回true(盒装值类型永远不会是空引用)
编辑:Marc对这个特定问题的答案摘要:重要的原因是这个词典< K,V>实现选择不允许使用“null”Nullable< T>实例作为键.因为MSIL盒指令对Nullable< T>给出特殊处理.值类型,对于所有值类型,检查不一定是徒劳的.
Nullable< T>是一个struct / value-type,可以为null(取决于你对null的定义;但肯定它可以为null).并非所有TKey都是值类型(字符串可能是最常见的TKey).这里要求密钥不为空;所以它确实需要验证.
实际上,拳击没有人们想象的那么糟糕;即使盒装,也将收集gen-0.它可以通过泛型(例如EqualityComparer< T>确实 – 通过一些不同的子类)进行特殊情况,但这看起来有点过分.
JIT也可以删除空检查.我可以在这里说,虽然这经常引用,但我已经看到了无效检查超出JIT删除能力的情况.