你如何在C#中使用“内联函数”?我认为我不理解这个概念。他们喜欢匿名方法吗?像lambda函数一样?
注意:答案几乎完全处理inline functions的能力,即“用被调用者的身体替换函数调用站点的手动或编译器优化”。如果您对anonymous (a.k.a. lambda) functions感兴趣,请参阅@jalf's answer或What is this 'Lambda' everyone keeps speaking of?。
答案 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>
编辑:澄清一下,他们需要谨慎使用两个主要原因:
最好不要管闲事,让编译器完成其工作,然后分析并确定内联是否是最适合您的解决方案。当然,有些事情只是内联才有意义(尤其是数学运算符),但让编译器处理它通常是最好的做法。
答案 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
}