我正在做一些关于装箱/拆箱的阅读,事实证明,如果你做一个普通的String.Format()
你在你的object[]
参数列表中有一个值类型,它将导致一个装箱操作.例如,如果您正在尝试打印出整数的值并执行此操作string.Format("My value is {0}",myVal)
,则会将其粘贴myVal
int
到一个框中并在其ToString
上运行该函数.
浏览,我发现了这篇文章.
看来你可以简单地通过.ToString
在将值传递给string.Format函数之前执行值类型来避免拳击惩罚:string.Format("My value is {0}",myVal.ToString())
Mer*_*ham 16
编译器不会为你执行此操作,因为string.Format
需要a params Object[]
.拳击发生是因为转换为Object
.
我不认为编译器倾向于特殊情况方法,因此在这种情况下它不会删除装箱.
是的,在许多情况下,如果你ToString()
先打电话,编译器就不会做拳击.如果它使用Object
我认为仍然需要的实现.
最终,string.Format
格式字符串本身的解析将比任何装箱操作慢得多,因此开销可以忽略不计.
Mar*_*ell 12
1:是的,只要 value-type覆盖ToString()
,所有内置类型都会覆盖.
2:因为规范中没有定义这样的行为,并且params object[]
(wrt值类型)的正确处理是:拳击
string.Format就像任何其他不透明方法一样; 这样做的事实对编译器来说是不透明的.如果模式包含类似的格式{0:n2}
(这需要特定的转换,而不仅仅是ToString()
),这在功能上也是不正确的.试图理解模式是不可取的和不可靠的,因为模式可能直到运行时才知道.
首先是简单的.编译器不转的原因string.Format("{0}", myVal)
为string.Format{"{0}", myVal.ToString())
,是没有任何理由为什么它应该.应该BlahFooBlahBlah(myVal)
变成BlahFooBlahBlah(myVal.ToString())
什么?也许这会有相同的效果,但为了更好的性能,但它可能会引入一个错误.编译错误!没有饼干!
除非可以从一般原则中推断出某些东西,否则编译器应该单独留下.
现在有趣的一点IMO:为什么前者导致拳击而后者没有.
对于前者,由于唯一匹配的签名是string.Format(string, object)
整数必须转换为要传递给方法的对象(盒装),该方法期望接收字符串和对象.
这个的另一半,为什么不myVal.ToString()
包装?
当编译器遇到这段代码时,它具有以下知识:
现在,通常C#编译器callvirt
用于所有方法调用有两个原因.首先,有时候你确实希望它成为一个虚拟的电话.第二个是(更有争议的)他们决定禁止对null引用进行任何方法调用,并且callvirt
有一个内置的测试.
但在这种情况下,这些都不适用.不能有更多派生类覆盖Int32.ToString(),myVal不能为null.因此它可以引入一个通过无拳击call
的ToString()
方法Int32
.
这种组合(值不能为空,则方法不能被重写别处)仅参考类型出现常常要少得多,所以编译器不能把它作为多优点然后(它也不会花费高达,因为他们不必被装箱).
如果Int32
继承方法实现,则不是这种情况.例如myVal.GetType()
,盒子myVal
里没有Int32
覆盖 - 不可能,它不是虚拟的 - 所以它只能myVal
通过装箱作为对象来处理.
事实上,这意味着C#编译器将callvirt
用于非虚拟方法,有时call
用于虚拟方法,这一点并非毫无讽刺意味.
*请注意,即使是可设置为null的可空整数也与此方面的空引用不同.
归档时间: |
|
查看次数: |
4192 次 |
最近记录: |