C# 中的 var 关键字会导致装箱吗?
我的老板禁止我使用 var
因为它会导致拳击并减慢应用程序的速度。
这是真的吗?
My boss forbids me to use var
as it would cause boxing and slowing down the app.
Is that true?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
一种可能有效的方法是编写这两个方法:
编译,并使用 ildasm 来检查生成的 CIL。给你的老板看看。
编辑 @ck 已完成除最后一项之外的所有操作步骤给你:)
An approach that might work is to write these two methods:
Compile, and use
ildasm
to examine the produced CIL. Show your boss.edit @ck has done all but the last step for you :)
根据 Aakash 的回答,这里是 IL:(感谢 LINQPad)
Following on from Aakash's answer, here is the IL: (thanks LINQPad)
为什么那么多人骂老板是傻子?兄弟们,革命吧!
您的老板需要阅读文档。
var
使编译器通过查看初始化表达式的静态类型来确定变量类型。无论您手动指定类型还是使用 var 并让编译器为您计算出来,在运行时都没有丝毫区别。更新 在该问题下的评论中,Hans Passant 问道
强制进行此类转换的自包含表达式的一个示例是:
但这与:
换句话说,这实际上与
var
没有任何关系。我的初始化表达式的结果是object
,因此var
必须使用它作为变量的类型。不可能是别的什么。Why are so many people cursed with bosses who are dumb? Revolution, brothers!
Your boss needs to read the documentation.
var
causes the compiler to figure out the variable type by looking at the static type of the initialization expression. It doesn't make the slightest difference at runtime whether you specify the type by hand or you usevar
and let the compiler figure it out for you.Update In a comment under the question, Hans Passant asks
An example of a self-contained expression that forces such a conversion is:
But that is just identical to:
In other words, this doesn't really have anything to do with
var
. The result of my initializer expression isobject
, hencevar
has to use that as the type of the variable. It couldn't be anything else.这根本不是真的。
var
只是意味着“亲爱的编译器,我知道类型是什么,你也知道,所以让我们继续吧。”它使代码更短,并且有些人发现这更具可读性(其他人发现它的可读性较差),但没有任何性能损失。
That's not true at all.
var
just means "dear compiler, I know what the type is, and so do you, so let's just move on shall we."It makes the code shorter and some find this more readable (others find it less readable), but there's no performance penalty whatsoever.
也许您的老板是一位熟悉
VARIANT
类型的老 Visual Basic(如 <= 6.0)程序员。如果您没有在DIM
语句中显式指定变量的类型,则它是一个VARIANT
,它是一种union
(如果我)正确回忆。将此类变量传递给函数时,您可以将其视为一种“装箱”和“拆箱”。有时人们会感到困惑。向您的老板询问他的 Visual Basic 战争故事。倾听、学习并同时赢得一些同情!当您离开办公室时,您可能会指出,c# 编译器在编译时就计算出这些内容,并且“装箱”不再是问题。
不要指望您的老板必须跟上语言/API 的最新变化。这并不是因为愚蠢。这是关于还有其他事情要做。例如,他的工作。
编辑:正如下面的评论所述,告诉您不要出于错误的原因使用
var
可能不是他的工作......Maybe your boss is an old Visual Basic (as in <= 6.0) programmer used to the
VARIANT
type. If you didn't specify the type of your variable explicitly in yourDIM
statement, it was aVARIANT
which is a sort ofunion
if I recall correctly. You could view this as a sort of "boxing" and "unboxing" when passing such variables to functions.Sometimes people get confused. Ask your boss about his Visual Basic war stories. Listen, learn and earn some sympathy at the same time! As you leave the office you could point out that the c# compiler figures this stuff out at compile time and that "boxing" isn't an issue anymore.
Don't expect your boss to have to keep up with the newest changes to languages/APIs. This isn't about being dumb. It's about having other stuff to do. His job, for instance.
Edit: As noted in comments below, though, telling you not to use
var
for the wrong reasons is probably not his job...实际上,var 在一些非常特殊的情况下也可以避免装箱。
结果如下 IL:
请注意,第二个(var 赋值)知道此返回值是 List 内部的值类型(结构),并且可以更有效地使用它 - 即使 List.GetEnumerator 的协定返回 IEnumerator。这将删除该结构上的装箱操作,并产生更高效的代码。
这就是为什么,例如,在下面的代码中, foreach 循环和第一个 using/while 对不会导致垃圾(由于缺少装箱),但第二个 using/while 循环却会导致垃圾(因为它对返回的结构进行装箱) :
另请注意,将其从“List”更改为“IList”将破坏此优化,因为 IList 只能推断 IEnumerator 类型的接口正在返回。使用 List 变量,编译器可以更加智能,可以看到唯一有效的返回值是 [mscorlib]System.Collections.Generic.List`1/Enumerator,因此可以优化调用来处理此问题。
虽然我知道这是一种非常有限的情况,但它可能是一个重要的情况,尤其是在不执行完整增量垃圾收集并暂停线程以执行标记/扫描的设备上。
Actually, var can also avoid boxing in some very specific instances.
Results in the following IL:
Note that the 2nd one (the var assignment) knows that this return value is a valuetype (struct) from inside List and can more efficiently use it - even though the contract from List.GetEnumerator returns an IEnumerator. This will remove the boxing operation on that struct and results in more efficient code.
This is why, for instance, in the following code the foreach loop and the first using/while pair doesn't cause garbage (due to a lack of boxing) but the 2nd using/while loop does (since it boxes the returned struct):
Note also that changing this from a "List" to an "IList" will break this optimization since the IList can only infer that an interface of type IEnumerator is coming back. With the List variable the compiler can be smarter and can see that the only valid return value is a [mscorlib]System.Collections.Generic.List`1/Enumerator and can therefore optimize the call to handle this.
While I understand that this is a very limited case, it may be an important one especially on devices that don't do full incremental garbage collection and pause your threads to do a mark/sweep.