[英]Inline functions in C#?
你如何在 C# 中執行“內聯函數”? 我不認為我理解這個概念。 它們像匿名方法嗎? 像 lambda 功能?
注意:答案幾乎完全涉及內聯函數的能力,即“用被調用者的主體替換 function 調用站點的手動或編譯器優化”。 如果您對匿名(又名 lambda)函數感興趣,請參閱@jalf 的回答或每個人都在談論的“Lambda”是什么? .
最后,在 .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 . 以前在這里使用“力”。 由於有一些反對票,我將嘗試澄清該術語。 正如在評論和文檔中一樣, The method should be inlined if possible.
, The method should be inlined if possible.
特別是考慮到 Mono(它是開放的),考慮到內聯或更通用的技術限制(例如虛函數),存在一些特定於 Mono 的技術限制。 總的來說,是的,這是對編譯器的一個提示,但我想這就是所要求的。
內聯方法只是一種編譯器優化,其中函數的代碼被滾動到調用者中。
在 C# 中沒有執行此操作的機制,並且在支持它們的語言中應謹慎使用它們——如果您不知道為什么應該在某處使用它們,那么它們就不應該使用。
編輯:為了澄清,有兩個主要原因需要謹慎使用它們:
最好不要管它,讓編譯器完成它的工作,然后分析並確定內聯是否是最適合您的解決方案。 當然,有些事情內聯才有意義(尤其是數學運算符),但讓編譯器處理它通常是最佳實踐。
更新:根據konrad.kruczynski 的回答,以下適用於 .NET 版本(包括 4.0)。
您可以使用MethodImplAttribute 類來防止方法被內聯...
[MethodImpl(MethodImplOptions.NoInlining)]
void SomeMethod()
{
// ...
}
...但沒有辦法做相反的事情並強制它內聯。
你混淆了兩個不同的概念。 函數內聯是一種編譯器優化,對語義沒有影響。 無論是否內聯,函數的行為都是相同的。
另一方面,lambda 函數純粹是一個語義概念。 對它們應該如何實現或執行沒有要求,只要它們遵循語言規范中規定的行為。 如果 JIT 編譯器喜歡,它們可以被內聯,如果不喜歡,則不可以。
C# 中沒有 inline 關鍵字,因為它是一種通常可以留給編譯器的優化,尤其是在 JIT 語言中。 JIT 編譯器可以訪問運行時統計信息,這使它能夠比編寫代碼時更有效地決定要內聯的內容。 如果編譯器決定內聯一個函數,那么無論哪種方式你都無能為力。 :)
科迪說得對,但我想提供一個內聯函數是什么的例子。
假設您有以下代碼:
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() 也從其他地方調用,它也可能會這樣做。
編輯以顯示更可能被內聯的場景。
你是說 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
}
是的,唯一的區別是它返回一個值。
簡化(不使用表達式):
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);
我希望這有幫助。
有時我確實希望強制代碼內聯。
例如,如果我有一個復雜的例程,其中在一個高度迭代的塊中做出了大量決策,並且這些決策導致要執行的類似但略有不同的操作。 例如,考慮一個復雜的(非 DB 驅動的)排序比較器,其中排序算法根據許多不同的不相關標准對元素進行排序,例如如果根據快速語言的語法和語義標准對單詞進行排序,則可能會這樣做識別系統。 我傾向於編寫輔助函數來處理這些操作,以保持源代碼的可讀性和模塊化。
我知道這些輔助函數應該是內聯的,因為如果代碼永遠不需要被人類理解,那么這就是編寫代碼的方式。 我當然想確保在這種情況下沒有函數調用開銷。
聲明“最好不要管這些事情,讓編譯器完成工作......”(Cody Brocious)完全是垃圾。 我已經編寫了 20 年的高性能游戲代碼,但我還沒有遇到一個“足夠聰明”的編譯器,可以知道哪些代碼應該被內聯(函數)。 在 c# 中有一個“內聯”語句會很有用,事實是編譯器沒有它需要的所有信息來確定在沒有“內聯”提示的情況下應該始終內聯或不內聯哪個函數。 當然,如果函數很小(訪問器),那么它可能會自動內聯,但如果它是幾行代碼呢? 廢話,編譯器無法知道,你不能把它留給編譯器來優化代碼(超越算法)。
我知道這個問題是關於 C# 的。 但是,您可以使用 F# 在 .NET 中編寫內聯函數。 請參閱: 在 F# 中使用 `inline`
不,C# 中沒有這樣的構造,但是 .NET JIT 編譯器可以決定在 JIT 時間執行內聯函數調用。 但我實際上不知道它是否真的在做這樣的優化。
(我認為它應該:-))
如果您的程序集將被生成,您可能需要查看 TargetedPatchingOptOut。 這將幫助 ngen 決定是否內聯方法。 MSDN參考
盡管如此,它仍然只是一個聲明性的優化提示,而不是一個命令式命令。
Lambda 表達式是內聯函數! 我認為,C# 沒有像 inline 之類的額外屬性!
C# 不支持像 python 這樣的動態語言那樣的內聯方法(或函數)。 但是,匿名方法和 lambdas 可用於類似目的,包括當您需要訪問包含方法中的變量時,如下例所示。
static void Main(string[] args)
{
int a = 1;
Action inline = () => a++;
inline();
//here a = 2
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.