c#中的内联函数?

如何在c#中做“内联函数”?我想我不明白这个概念。它们像匿名方法吗?比如函数?

请注意:答案几乎完全涉及内联函数的能力,即。用被调用者的主体替换函数调用站点的手册或编译器优化。如果你对匿名(又名lambda)函数感兴趣,请参阅@jalf的回答这是什么'Lambda'大家都在说?

210901 次浏览

内联方法只是一种编译器优化,将函数的代码滚入调用方。

在c#中没有这样做的机制,在支持它们的语言中应该谨慎使用它们——如果你不知道为什么应该在某个地方使用它们,那么就不应该使用它们。

编辑:要澄清的是,有两个主要原因需要谨慎使用:

  1. 在不必要的情况下使用内联可以很容易地生成大量二进制文件
  2. 从性能的角度来看,编译器往往比您更了解什么时候应该内联

最好不去管它,让编译器完成它的工作,然后进行分析并确定内联是否是最适合您的解决方案。当然,有些东西内联是有意义的(特别是数学运算符),但让编译器处理通常是最佳实践。

Lambda表达式是内联函数!我认为,c#没有额外的属性,比如内联或类似的东西!

你是指c++意义上的内联函数吗?其中一个正常函数的内容被自动内联复制到callsite?最终的结果是,在调用函数时实际上不会发生函数调用。

例子:

inline int Add(int left, int right) { return left + right; }

如果是,那么没有,c#中没有与之等价的东西。

或者你是指在另一个函数中声明的函数吗?如果是的话,c#通过匿名方法或lambda表达式来支持。

例子:

static void Example() {
Func<int,int,int> add = (x,y) => x + y;
var result = add(4,6);  // 10
}

没错,唯一的区别是它返回一个值。

简化(不使用表达式):

List<T>.ForEach执行一个操作,它不期望返回结果。

所以Action<T>委托就足够了。说:

List<T>.ForEach(param => Console.WriteLine(param));

就等于说:

List<T>.ForEach(delegate(T param) { Console.WriteLine(param); });

不同之处在于参数类型和委托声明是根据用法推断的,在简单的内联方法上不需要花括号。

List<T>.Where接受一个函数,期待一个结果。

因此,将期望Function<T, bool>:

List<T>.Where(param => param.Value == SomeExpectedComparison);

也就是:

List<T>.Where(delegate(T param) { return param.Value == SomeExpectedComparison; });

你也可以内联声明这些方法,并将它们赋值给变量IE:

Action myAction = () => Console.WriteLine("I'm doing something Nifty!");


myAction();

Function<object, string> myFunction = theObject => theObject.ToString();


string myString = myFunction(someObject);

我希望这能有所帮助。

Cody说得对,但我想提供一个内联函数是什么的例子。

假设你有这样的代码:

private void OutputItem(string x)
{
Console.WriteLine(x);


//maybe encapsulate additional logic to decide
// whether to also write the message to Trace or a log file
}


public IList<string> BuildListAndOutput(IEnumerable<string> x)
{  // let's pretend IEnumerable<T>.ToList() doesn't exist for the moment
IList<string> result = new List<string>();


foreach(string y in x)
{
result.Add(y);
OutputItem(y);
}
return result;
}

编译器Just-In-Time优化器可以选择修改代码,以避免在堆栈上重复调用OutputItem(),这样就好像你写的代码是这样的:

public IList<string> BuildListAndOutput(IEnumerable<string> x)
{
IList<string> result = new List<string>();


foreach(string y in x)
{
result.Add(y);


// full OutputItem() implementation is placed here
Console.WriteLine(y);
}


return result;
}

在本例中,我们可以说OutputItem()函数是内联的。注意,即使从其他地方也调用OutputItem(),它也可能这样做。

经过编辑以显示更可能内联的场景。

你把两个不同的概念混在一起了。函数内联是对语义没有影响的编译器优化。不管函数是否内联,它的行为都是一样的。

另一方面,lambda函数纯粹是一个语义概念。对于它们应该如何实现或执行没有要求,只要它们遵循语言规范中规定的行为即可。如果JIT编译器喜欢,它们可以内联,如果不喜欢,则不可以。

c#中没有内联关键字,因为这是一种通常可以留给编译器的优化,尤其是在JIT语言中。JIT编译器可以访问运行时统计信息,这使它能够比编写代码时更有效地决定内联哪些内容。函数将内联,如果编译器决定,没有什么你可以做的任何方式。:)

不,c#中没有这样的构造,但是. net JIT编译器可以决定在JIT时间执行内联函数调用。但我实际上不知道它是否真的在做这样的优化。
(我认为它应该:-))

c#不像python这样的动态语言那样支持内联方法(或函数)。然而,匿名方法和lambdas可以用于类似的目的,包括当您需要访问包含方法中的变量时,如下例所示。

static void Main(string[] args)
{
int a = 1;


Action inline = () => a++;
inline();
//here a = 2
}

更新:根据konrad.kruczynski的回答,对于。net 4.0以下版本是正确的。

你可以使用MethodImplAttribute类防止方法从内联…

[MethodImpl(MethodImplOptions.NoInlining)]
void SomeMethod()
{
// ...
}

...但是没有办法做相反的事情,它是内联的。

在某些情况下,我确实希望强制代码内联。

例如,如果我有一个复杂的例程,在一个高度迭代的块中有大量的决策,这些决策导致要执行的类似但略有不同的操作。例如,考虑一个复杂的(非DB驱动的)排序比较器,其中排序算法根据许多不同的不相关的标准对元素进行排序,就像一个快速语言识别系统根据语法和语义标准对单词进行排序一样。我倾向于编写helper函数来处理这些操作,以保持源代码的可读性和模块化。

我知道那些辅助函数应该是内联的,因为这是编写代码的方式,如果它永远不需要被人类理解的话。在这种情况下,我当然希望确保没有函数调用开销。

语句“最好不要管这些事情,让编译器来做。”(Cody Brocious)完全是垃圾。我已经编写了20年的高性能游戏代码,但我还没有遇到一个“足够聪明”的编译器,可以知道哪些代码应该内联(函数)。在c#中有一个“内联”语句是很有用的,事实是编译器没有所有它需要的信息来决定哪个函数应该总是内联的,或者没有“内联”提示。当然,如果函数很小(accessor),那么它可能会自动内联,但如果它是几行代码呢?胡说八道,编译器没有办法知道,你不能把它留给编译器来优化代码(超越算法)。

如果您的程序集将被ngen-ed,您可能想要查看TargetedPatchingOptOut。这将帮助ngen决定是否内联方法。MSDN参考

这仍然只是一个声明性的优化提示,而不是命令式命令。

最后,在。net 4.5中,CLR允许使用MethodImplOptions.AggressiveInlining值提示/建议__abc1方法内联。它也可以在Mono的主干中使用(今天提交)。

// The full attribute usage is in mscorlib.dll,
// so should not need to include extra references
using System.Runtime.CompilerServices;


...


[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MyMethod(...)

1。以前“force"在这里使用过。我会试着解释一下这个术语。特别是考虑到Mono(它是开放的),在考虑内联或更一般的(如虚函数)时,有一些特定于Mono的技术限制。总的来说,是的,这是对编译器的一个提示,但我猜这是要求的。

我知道这个问题是关于c#的。然而,你可以用f#在。net中编写内联函数。看:在f#中使用' inline '