【问题标题】:Do anonymous methods inline?匿名方法是否内联?
【发布时间】:2017-03-03 18:49:45
【问题描述】:

首先,这不是这个问题的欺骗:

Are anonymous methods defined inline?

我认为提问者在问一个不同的问题。

我在询问方法内联,在编译过程中,对方法的调用被方法的实际替换。

我对匿名方法的理解是,它们实际上编译为具有编译器指定名称的具体方法。这样做是为了减少堆栈开销。编译匿名方法时,它们是否内联一样?

【问题讨论】:

  • 任何数量的免费 .NET 反编译器都可以为您提供答案。

标签: .net inline anonymous-methods


【解决方案1】:

匿名方法的工作方式与普通方法完全相同 - 如果 JIT 编译器决定内联它们,它们可以被内联。

但是,您很可能不是直接调用匿名方法 - 您调用的是指向匿名方法的委托。在这种情况下,与任何其他委托调用一样,编译器无法内联任何内容,因为它在编译时(或 JIT 时)不知道实际将调用哪个方法。

我猜你对泛型在 .NET 中的工作方式感到困惑,而不是显式地使用匿名方法,尤其是与 C++ 的模板相比 - 例如,如果我在 C# 中使用 collection.Select(i => i.SomeProperty),那么仍然只有一种方法 Select[ 1];当有其他 Select 调用将不同的函数作为参数时,您将如何内联 i => i.SomeProperty 方法?相反,在 C++ 中使用模板允许内联“函数”参数,因为模板只是编译时代码生成功能;每次在 C++ 中使用类似的 Select 模板都会给你一段单独的代码,不涉及任何方法调用。

不用说,这只是一个实现细节。未来的编译器可以通过假装它不是委托并内联 Select 方法本身来内联方法调用。

[1] - 从技术上讲,在 JIT 编译期间,对于不同类型的参数,Select 方法可能有多个版本 - 不过,这与这种情况无关;它仍然没有为每个可能的论点制定不同的方法。

【讨论】:

  • 在 JIT 编译期间,有多个版本的 Select 方法,所以(在一般情况下)我不明白为什么 JIT 编译器能够内联一个(具体的)泛型方法。然而,LINQ 是一个相当特殊的情况,因为IEnumerable<T> 发生了很多管道问题,而且它是惰性评估的,所以我怀疑像Select 这样的任何扩展方法在实践中都会被内联。我能想到的唯一情况是立即使用ToList,即items.Select(i => i.x).ToList() 完全内联到循环中。
  • (反正我的意思是Select和其他LINQ方法特别难内联)
  • @Groo 同意,如果不是不可能的话,内联实际的 LINQ 扩展方法会很困难。但是,我的问题是指匿名代表本身的内联。如果它没有内联,调用 .Select() 会在堆栈上添加两个调用,而如果匿名委托主体被内联,则只有一个。
  • @oscilatingcretin 不,您需要内联整个 Select 方法才能内联匿名方法。没有地方可以内联 to 方法 - 要么您需要为每个可能的参数有一个单独的 Select 方法,然后将其内联到 SelectForAnonymousMethod42 方法中,或者您需要内联两个方法。
  • @Groo 这就是为什么脚注说“从技术上讲,不同类型的参数可能有多个版本”。并且没有约定说“可枚举的对象被懒惰地评估”——如果它将每个可枚举对象更改为一个数组,或者批量处理枚举,那么运行时将完全在其权利范围内。您不应该在 C# 的更多功能部分中引起副作用,这是有原因的 - 您几乎无法保证可枚举的实际评估方式。
猜你喜欢
  • 2013-06-11
  • 1970-01-01
  • 2017-10-18
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
相关资源
最近更新 更多