【发布时间】:2019-01-18 17:28:50
【问题描述】:
我试图了解编译器对非常简单的一段代码做了什么:
if (group.ImageHeight > 1 && group.ImageWidth > 1)
{ //No code exists between the braces
}
在Debug配置中编译后,然后反编译我看到了这个:
if (group.ImageHeight <= 1 || group.ImageWidth <= 1);
反编译Release配置会导致
if (group.ImageHeight > 1)
{
int imageWidth = group.ImageWidth;
}
更完整的(原始)代码:
public class Group
{
public int ImageHeight { get; set; }
public int ImageWidth { get; set; }
}
//The following belongs to a different project than `Group`
static void Main(string[] args)
{
Group group = new Group();
MyMethod(group);
}
static void MyMethod(Group group)
{
if (group.ImageHeight > 1 && group.ImageWidth > 1)
{
}
}
以下是我目前的猜测和观察:
- 当我第一次启动它时,我希望编译器完全删除整个语句。我认为这不是因为对属性的评估可能会产生副作用。
- 我认为
group类型属于我的解决方案中的另一个项目很重要。我这样说是因为编译器可能无法“知道”将来评估属性的副作用是什么。例如,我可以在编译后替换包含group定义的DLL。 - 在
Release配置中,可能的副作用似乎与我的代码相同:评估ImageHeight,如果满足> 1条件将评估ImageWidth(尽管通过分配而不是比较)李>
现在,针对我的具体问题:
- 为什么
Release配置使用赋值(int imageWidth = group.ImageWidth)而不是我原来的比较?执行作业是否更快? - 为什么
Debug配置完全改变了副作用的可能性?在此配置中,ImageHeight和ImageWidth将始终被评估。
【问题讨论】:
-
由于组在 Main() 中声明并且逻辑上在堆上,并且由于 MyMethod 是静态的并且在“全局”主变量组中传递...您正在为优化器提供免费通行证做一些大的假设。如果变量和代码块进出范围,您可能会看到更接近预期的结果。此外,您的 int 属性访问器中没有代码,这是另一个免费通行证。那是我的 2 位。
-
请记住,C# 编译器本身并不倾向于进行大量“强”优化。很多更强大的优化都留给了 JIT 编译器。此外,您必须考虑到您使用的任何反编译器对您所看到的“之后”的影响与 C# 编译器一样大。如果你想知道 C# 编译器在做什么,你应该关注 IL 级别,而不是其他工具将 IL 重新解释为什么。
-
@Damien_The_Unbeliever 谢谢,这是有道理的,我会记住的。 IL 水平有点高出我的头...也许我应该学习这些天之一:)
-
是的,IL 是非常“简单”或非常“复杂”的事物之一。这在很大程度上取决于你是否“得到”Stack Machines
标签: c# .net compiler-construction compiler-optimization