C#中的内联函数?

时间:2009-01-23 17:31:07

标签: c# optimization inline

你如何在C#中使用“内联函数”?我认为我不理解这个概念。他们喜欢匿名方法吗?像lambda函数一样?

注意:答案几乎完全处理inline functions的能力,即“用被调用者的身体替换函数调用站点的手动或编译器优化”。如果您对anonymous (a.k.a. lambda) functions感兴趣,请参阅@jalf's answerWhat is this 'Lambda' everyone keeps speaking of?

14 个答案:

答案 0 :(得分:355)

最后在.NET 4.5中,CLR允许使用MethodImplOptions.AggressiveInlining值提示/建议 1 方法内联。它也可以在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”。由于有一些downvotes,我会试着澄清这个词。正如在评论和文档中那样,The method should be inlined if possible.特别是考虑到Mono(开放),考虑内联或更一般的(如虚函数),存在一些特定于单一的技术限制。总的来说,是的,这是对编译器的暗示,但我想这就是要求的。

答案 1 :(得分:83)

内联方法只是一种编译器优化,其中函数的代码被卷入调用者。

在C#中没有机制可以做到这一点,并且它们在支持它们的语言中被谨慎使用 - 如果你不知道为什么它们应该在某个地方使用,它们不应该是。< / p>

编辑:澄清一下,他们需要谨慎使用两个主要原因:

  1. 在没有必要的情况下使用内联来制作大量二进制文件很容易
  2. 从性能的角度来看,编译器往往比你应该知道更好的内容
  3. 最好不要管闲事,让编译器完成其工作,然后分析并确定内联是否是最适合您的解决方案。当然,有些事情只是内联才有意义(尤其是数学运算符),但让编译器处理它通常是最好的做法。

答案 2 :(得分:50)

更新:对于konrad.kruczynski's answer,以下版本适用于4.0及以下版本的.NET。

您可以使用MethodImplAttribute class 阻止方法进行内联...

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

...但是没有办法做相反的事情并且强制它被内联。

答案 3 :(得分:32)

你混淆了两个不同的概念。函数内联是一种编译器优化,它对语义没有影响。无论内联与否,函数的行为都相同。

另一方面,lambda函数纯粹是一种语义概念。只要它们遵循语言规范中规定的行为,就不需要如何实现或执行它们。如果JIT编译器感觉如此,则可以内联它们,如果没有,则可以内联。

C#中没有内联关键字,因为它是一种优化,通常可以留给编译器,特别是在JIT的语言中。 JIT编译器可以访问运行时统计信息,这使得它可以比编写代码时更有效地决定内联内容。如果编译器决定使用函数,那么无论如何都无法对它进行任何操作。 :)

答案 4 :(得分:21)

你的意思是C ++意义上的内联函数吗?其中普通函数的内容是否自动内嵌到调用点?最终结果是在调用函数时实际上没有发生函数调用。

示例:

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
}

答案 5 :(得分:20)

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;
}

编译器实时优化器可以选择改变代码以避免重复调用堆栈上的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(),它也可能会这样做。

编辑以显示更可能被内联的方案。

答案 6 :(得分:6)

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

简化(不使用表达式):

List<T>.ForEach采取行动,不期望返回结果。

所以Action<T>代表就够了......说:

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

与说法相同:

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

区别在于param类型和委托decleration是由用法推断的,并且在简单的内联方法中不需要括号。

在哪里

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);

我希望这会有所帮助。

答案 7 :(得分:2)

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

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

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

答案 8 :(得分:2)

声明“最好将这些事情单独留下并让编译器完成工作......”(Cody Brocious)是完全无懈可击的。我已经编写了20年的高性能游戏代码,我还没有遇到一个“足够智能”的编译器,无法知道哪些代码应该内联(函数)。在c#中使用“内联”语句会很有用,事实上,如果没有“内联”提示,编译器就不会拥有确定哪个函数应该始终内联所需的所有信息。当然,如果函数很小(访问器),那么它可能会自动内联,但如果只是几行代码呢?没什么,编译器无法知道,你不能把它留给编译器来优化代码(超出算法)。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

如果您的程序集已被添加,您可能需要查看TargetedPatchingOptOut。这将有助于ngen决定是否内联方法。 MSDN reference

它仍然只是一个声明性提示,但不是命令性的命令。

答案 11 :(得分:0)

我知道这个问题是关于C#的。但是,您可以使用F#在.NET中编写内联函数。见:Use of `inline` in F#

答案 12 :(得分:-6)

Lambda表达式是内联函数!我认为,C#没有像内联这样的额外属性!

答案 13 :(得分:-6)

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

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

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