您如何在C#中执行“内联函数”?我认为我不了解这个概念。他们喜欢匿名方法吗?像lambda函数一样?
注意:答案几乎完全涉及内联函数的功能,即“手动或编译器优化,将被调用者的主体替换为函数调用站点”。如果您对匿名(又名lambda)函数感兴趣,请参阅@jalf的答案或每个人都在谈论的“ Lambda”是什么?。
您如何在C#中执行“内联函数”?我认为我不了解这个概念。他们喜欢匿名方法吗?像lambda函数一样?
注意:答案几乎完全涉及内联函数的功能,即“手动或编译器优化,将被调用者的主体替换为函数调用站点”。如果您对匿名(又名lambda)函数感兴趣,请参阅@jalf的答案或每个人都在谈论的“ Lambda”是什么?。
Answers:
最后,在.NET 4.5中,CLR允许使用值暗示/建议1方法内联MethodImplOptions.AggressiveInlining
。它也可以在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。以前在这里使用“力”。由于有一些反对意见,我将尝试澄清这个词。如评论和文档中所述,The method should be inlined if possible.
特别是考虑到Mono(已公开),存在一些特定于Mono的技术限制,其中考虑了内联或更普遍的限制(例如虚函数)。总体而言,是的,这是对编译器的提示,但我想这正是所要的。
内联方法只是一种编译器优化,其中函数的代码将滚动到调用程序中。
在C#中没有执行此操作的机制,只能在支持它们的语言中少量使用它们-如果您不知道为什么应该在某些地方使用它们,则不应该使用它们。
编辑:澄清一下,有两个主要原因需要谨慎使用:
最好不要管它,让编译器完成工作,然后剖析并找出内联是否是最适合您的解决方案。当然,内联某些事情(特别是数学运算符)有意义,但是让编译器处理通常是最佳实践。
更新:根据konrad.kruczynski的回答,以下内容适用于4.0及以下版本的.NET。
您可以使用MethodImplAttribute类来防止内联方法。
[MethodImpl(MethodImplOptions.NoInlining)]
void SomeMethod()
{
// ...
}
...但没有办法做相反的,并迫使它内联。
GetExecutingAssembly
并GetCallingAssembly
根据方法是否内联可以给出不同的结果。强制使用非内联方法可以消除任何不确定性。
您正在混淆两个单独的概念。函数内联是一种编译器优化,对语义没有影响。无论是否内联,函数的行为都相同。
另一方面,lambda函数纯粹是一个语义概念。只要遵循语言规范中规定的行为,就无需实现或执行它们。如果JIT编译器喜欢,可以内联它们,否则,可以不使用它们。
C#中没有inline关键字,因为它是通常可以留给编译器的一种优化,尤其是在JIT语言中。JIT编译器可以访问运行时统计信息,从而使其能够比编写代码时更有效地决定内联哪些内容。如果编译器决定这样做,则将内联一个函数,而您对这两种方法均无能为力。:)
您是说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
}
科迪说的没错,但是我想提供一个内联函数的例子。
假设您有以下代码:
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(),也可能会这样做。
编辑以显示更可能内联的方案。
是确实,唯一的区别是它返回一个值。
简化(不使用表达式):
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 Brocious))是完全废话。我已经编写了高性能游戏代码已有20年了,但我还没有遇到一个“足够聪明”的编译器来知道应该内联哪些代码(函数)。在c#中使用“内联”语句将很有用,事实是,编译器只是不具备确定哪个函数应始终内联或不具有“内联”提示而始终内联所需的所有信息。当然,如果函数很小(访问器),那么它可能会自动内联,但是如果只有几行代码怎么办?毫无意义,编译器无法知道,您不能仅仅将其留给编译器以获取优化的代码(超出算法)。
Lambda表达式是内联函数!我认为C#没有内联之类的额外属性!
C#不像python之类的动态语言那样支持内联方法(或函数)。但是,匿名方法和lambda可以用于类似目的,包括当您需要访问包含方法中的变量时(如下面的示例)。
static void Main(string[] args)
{
int a = 1;
Action inline = () => a++;
inline();
//here a = 2
}