布尔与内存

时间:2014-11-10 06:26:42

标签: c# memory boolean

我们在工作中讨论了代码设计,其中一个问题是在处理对这样的布尔方法的调用时的响应:

bool ok = IsEverythingOK();

if(ok)
{
   //do somehthing
}

我的一位同事坚持认为我们跳过了额外的变量ok并写了

if(IsEverythingOK())
{
   //do somehthing
}

因为他说使用" bool ok" -statement是记忆性不好。

我们应该使用哪一个?

4 个答案:

答案 0 :(得分:5)

解释你的问题:

  

使用本地变量是否有成本?

因为C#和.NET设计得很好,我的期望是使用你描述的局部变量没有或可以忽略不计的成本,但让我尝试用一​​些事实来支持这个期望。

以下C#代码

if (IsEverythingOk()) {
  ...
}

将编译为此(简化)IL(启用优化)

call        IsEverythingOk
brfalse.s   AfterIfBody
... if body

使用本地变量

var ok = IsEverythingOk();
if (ok) {
  ...
}

你得到了这个优化(和简化)的IL:

call        IsEverythingOk
stloc.0
ldloc.0
brfalse.s   AfterIfBody
... if body

从表面上看,这似乎效率稍低,因为返回值存储在堆栈上然后重新执行,但JIT编译器也会执行一些优化。

您可以通过调试启用本机代码调试的应用程序来查看生成的实际机器代码。您必须使用发布版本执行此操作,并且还必须关闭调试器选项,该选项会阻止对模块加载的JIT优化。现在,您可以在要检查的代码中放置断点,然后查看反汇编。请注意,JIT就像一个黑盒子,我在计算机上看到的行为可能与其他人在计算机上看到的行为不同。考虑到这个免责声明,我为两个版本的代码获得的汇编代码是(执行调用的方式略有不同):

call        IsEverythingOk
test        eax,eax  
je          AfterIfBody

因此JIT将优化额外不必要的IL。实际上,在我最初的实验中,方法IsEverythingOk返回true,JIT能够完全优化分支。当我切换到返回方法中的字段时,JIT将内联调用并直接访问该字段。

底线:你应该期望JIT至少优化瞬态局部变量之类的简单事物,即使代码产生了一些看似不必要的额外IL。

答案 1 :(得分:3)

这完全取决于你是否在循环中使用ok做任何事情。

bool ok = IsEverythingOK();

if(ok)
{
   //do somehthing
   ok = IsEverythingOK();
}

假设你在循环中没有对ok做任何事情,你可能会发现JIT编译器会转向:

bool ok = IsEverythingOK();

if(ok)
{
   //do somehthing
}

......本质上是:

if(IsEverythingOK())
{
   //do somehthing
}

...反正。

答案 2 :(得分:1)

如果您使用第一个解决方案,编译器当然会生成一些额外的IL代码步骤,因为它至少需要额外的stlocldloc命令,但如果仅出于性能原因,请忘记这些微内核(或纳秒)。

如果ok变量没有其他原因,我会更喜欢第二种解决方案,因为它更易于阅读。

答案 3 :(得分:1)

除非你有统一的编码标准,否则我会说这是首选。另一个提供了一个好处。

如果您期望或假设除了if子句之外的修改,那么这很好。虽然它确实在创建变量时创建了一个堆栈条目,但它会在方法范围之后被多处理。

bool ok = IsEverythingOK();

if(ok)
{
   //do somehthing
}

如果您只想将其用作验证,那就太棒了。虽然你的方法名称很短,但这是唯一的好处。但是,假设您在使用它之前访问类,如 _myLongNameInstance.IsEverythingOK()这会降低可读性,我会选择第一个,但在其他条件下,我会选择直接if。

if(IsEverythingOK())
{
   //do somehthing
}