C# 不需要作用域的性能

C# 不需要作用域的性能,c#,scope,readability,code-readability,C#,Scope,Readability,Code Readability,如果我创建了不必要的作用域,这会降低性能还是不好的做法? 我的意思是,创建作用域只是为了可读性: XmlElement header = list[0] as XmlElement; if (header == null) throw new Exception("Corrupt header."); { XmlElement subHeader = null; // ... } 这样它更清晰易读。为什么要避免这种情况?我刚刚意识到,让我相对较长的代码更具可读性会非常好。特别是因为这

如果我创建了不必要的作用域,这会降低性能还是不好的做法? 我的意思是,创建作用域只是为了可读性:

XmlElement header = list[0] as XmlElement;
if (header == null) throw new Exception("Corrupt header.");

{
    XmlElement subHeader = null; // ...
}
这样它更清晰易读。为什么要避免这种情况?我刚刚意识到,让我相对较长的代码更具可读性会非常好。特别是因为这种情况发生了不止一次,我必须加载一个主元素,然后它有一些子元素,我可以很容易地从视觉上分离出来


专业人士怎么说?

这不是更容易理解。您的示例代码显示了这一点

在我看来,这两组代码之间的差异令人困惑:

XmlElement header = list[0] as XmlElement;
if (header == null)
{
    XmlElement subHeader = null; // ...
}


XmlElement header = list[0] as XmlElement;
if (header == null) throw new Exception("Corrupt header.");
{
    XmlElement subHeader = null; // ...
}
此外,如果您的代码相对较长,那么应该将其分解为单独的方法,而不是按作用域块分组

现在,就性能而言。下面是一个简单的例子:

var text = "Hello";
Console.WriteLine(text);
这就变成了这个IL:

IL_0001:  ldstr       "Hello"
IL_0006:  stloc.0     // text
IL_0007:  ldloc.0     // text
IL_0008:  call        System.Console.WriteLine
如果我这样写代码:

var text = "Hello";
{
    Console.WriteLine(text);
}
IL变为:

IL_0001:  ldstr       "Hello"
IL_0006:  stloc.0     // text
IL_0007:  nop         
IL_0008:  ldloc.0     // text
IL_0009:  call        System.Console.WriteLine
IL_000E:  nop      
注意nop操作

对于每个作用域块,我在IL中得到一对新的nop操作。但这只发生在调试模式下。在释放模式下,nop操作被删除

为了测试调试模式下的性能差异,我编写了以下代码:

var sw = Stopwatch.StartNew();
var x = 0L;
for (var y = 0; y < 1000000000L; y++)
{
    {
        x += y;
    }
}
sw.Stop();
Console.WriteLine(x);
Console.WriteLine(sw.ElapsedMilliseconds);
有了额外的示波器,它在大约3550毫秒内持续运行。没有额外的示波器,它的运行时间约为3500毫秒。因此,性能差异约为1.5%。这只是在调试模式下


但是考虑到我的操作x+=y是如此微不足道,性能下降如此之小,您可能可以忽略正常代码中的性能差异。显然,在发布模式代码中完全忽略它。

不,没有性能影响。虽然你可能想考虑将代码分解成方法,但是如果你真的在阅读可读性之后,考虑不包括if动作抛出新的异常…在与条件相同的行上。特别是在这种情况下,当第一眼看到下面的代码块被附加到iff语句时,快速扫描代码,我会将您的代码块理解为属于if语句。这是一种非传统的格式。所以对我来说,这显然不是更好。希望您不认为越短越好。如果您需要多次对同一场景执行相同的验证,请考虑使用自定义构造函数扩展XmlElement类,该构造函数将list[0]的值作为参数,并在其中执行验证。如果需要,更短、更清晰的代码和单点验证将发生更改。在运行时唯一有影响的作用域是那些实际更改代码逻辑的作用域。像try/catch一样,使用{}锁定{}。if{}/else{}。不是这种。一定要小心,它不是更可读,任何人看到这将失去一分钟的生命试图找出你为什么这样做。那一分钟你欠他的,很难还清。很高兴知道,谢谢你的测试。我知道它的可读性不强,特别是在这个选择不好的场景中,但我很好奇。你确定你是在发布模式下编译的吗?我强烈怀疑这些nop指令仅仅是为了让您在附加的开口大括号上设置断点时设置断点。@Lucastrezesniewski-是的。你是对的。它们在释放模式下消失。+1。嗯,这改变了你文章的结论,我想=>没有任何区别。在我看来,你甚至应该删除基准测试,因为它在调试模式下是不相关的。@Lucastzesniewski-是的,它确实改变了结论,但我认为性能代码仍然强调了这样一个事实,即范围块在任何情况下都不会对性能产生任何影响,实际上不会产生任何影响。