根据我的理解,内联是编译器(在C#是虚拟机的情况下)通过在调用方法的每个位置插入方法体来替换方法调用.
假设我有以下程序:
static Main() { int number = 7; bool a; a = IsEven(number); Console.WriteLine(a); }
…方法的主体IsEven:
bool IsEven(int n) { if (n % 2 == 0) // Two conditional return paths return true; else return false; }
static Main() { int number = 7; bool a; if (number % 2 == 0) a = true; else a = false; Console.WriteLine(a); // Will print true if 'number' is even,otherwise false }
一个明显简单而正确的程序.
但是,如果我稍微调整一下IsEven的主体以包含绝对返回路径……
bool IsEven(int n) { if (n % 2 == 0) return true; return false; // <- Absolute return path! }
在某些情况下,我个人更喜欢这种风格.一些折射工具甚至可能会建议我将第一个版本更改为这个版本 – 但是当我试图想象这个方法在内联时的样子时我感到难过.
如果我们内联方法的第二个版本:
static Main() { int number = 7; bool a; if (number % 2 == 0) a = true; a = false; Console.WriteLine(a); // Will always print false! }
要问的问题是:
编译器/虚拟机如何处理内联具有绝对返回路径的方法?这样的事情似乎不太可能真正阻止方法内联,所以我想知道如何处理这些事情.也许内联的过程并不像这样简单?也许一个版本更有可能被VM内联?
编辑:
对两种方法进行概要分析(以及第一种方法的手动内联)显示性能没有差异,因此我只能假设这两种方法都以相同或相似的方式进行内联和工作(至少在我的VM上).
此外,这些方法非常简单并且看起来几乎可以互换,但是具有绝对返回路径的复杂方法可能更难以更改为没有绝对返回路径的版本.
解决方法
也就是说,通过考虑break关键字,您可以在C#术语中了解它是如何工作的.
考虑这样一种可能性:每个内联函数都不是简单地包含在while(true)循环中(或者执行while(false)循环) – 并且每个源返回都被转换为localVar = result;打破;一套陈述.然后你得到这样的东西:
static Main() { int number = 7; bool a; while (true) { if (number % 2 == 0) { a = true; break; } a = false; break; } Console.WriteLine(a); // Will always print the right thing! Yey! }
类似地,在生成程序集时,您将看到生成了大量的jmps – 这些是break语句的道德等价物,但它们更灵活(将它们视为匿名的getos或其他东西).
所以你可以看到,抖动(以及编译为本机的任何编译器)都有很多可以用来做“正确的事情”的工具.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。