首页 文章

C#中的内联函数?

提问于
浏览
243

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

Note :答案几乎完全处理inline functions的能力,即"a manual or compiler optimization that replaces a function call site with the body of the callee."如果您对anonymous (a.k.a. lambda) functions感兴趣,请参阅@jalf's answerWhat is this 'Lambda' everyone keeps speaking of? .

14 回答

  • 49

    最后在.NET 4.5中,CLR允许使用MethodImplOptions.AggressiveInlining值来提示/ suggest1方法内联 . 它也可以在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(开放),考虑内联或更普遍的(如虚拟函数),存在一些特定于单一的技术限制 . 总的来说,是的,这是对编译器的暗示,但我想这就是要求的 .

  • 0

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

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

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

    • 没有必要's easy to make massive binaries by using inline in cases where it'

    • 从性能的角度来看,编译器往往比你应该知道更好

    最好不要管它,让编译器完成它的工作,然后分析并确定内联是否是最适合你的解决方案 . 当然,有些事情只是有意义内联(特别是数学运算符),但让编译器处理它通常是最好的做法 .

  • 6

    Update: Per konrad.kruczynski's answer,以下版本适用于4.0及以下版本的.NET .

    您可以使用MethodImplAttribute class来防止方法被内联...

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

    ......但是没有办法做相反的事情并迫使它被内联 .

  • 21

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

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

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

  • 0

    你的意思是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
    }
    
  • 2

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

    compilerJust-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(),它也可能会这样做 .

    编辑以显示更可能被内联的场景 .

  • 20

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

    简化(不使用表达式):

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

    我希望这有帮助 .

  • 31

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

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

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

  • 0

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

  • -7

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

  • 347

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

    尽管如此,它仍然只是一个声明性的提示,而不是命令性命令 .

  • 82

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

  • -6

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

    static void Main(string[] args)
    {
        int a = 1;
    
        Action inline = () => a++;
        inline();
        //here a = 2
    }
    
  • 2

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

相关问题