web-dev-qa-db-ja.com

C#のインライン関数?

C#で「インライン関数」をどのように行いますか?私はこの概念を理解しているとは思わない。それらは匿名メソッドのようなものですか?ラムダ関数が好きですか?

:答えは、ほぼ完全に インライン関数 の機能を扱っています。つまり、「関数を置き換える手動またはコンパイラの最適化呼び出し先の本文でサイトを呼び出します。」 匿名(別名、ラムダ)関数 に興味がある場合は、 @ jalfの答え または この「ラムダ」とは誰もが言い続けているもの を参照してください。

252
Dinah

最後に、.NET 4.5では、CLRによってヒント/提案が可能になりました1 MethodImplOptions.AggressiveInlining valueを使用したメソッドのインライン化。また、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」がここで使用されていました。いくつかのダウン票があったので、この用語を明確にしようとします。コメントとドキュメントのThe method should be inlined if possible.のように、特にMono(オープン)を考慮すると、インライン化またはより一般的なもの(仮想関数など)を考慮するモノ固有の技術的な制限がいくつかあります。全体的に、はい、これはコンパイラへのヒントですが、私はそれが求められたものだと思います。

358

インラインメソッドは、関数のコードが呼び出し元にロールされるコンパイラ最適化です。

C#でこれを行うメカニズムはありません。また、サポートされている言語では控えめに使用する必要があります。

編集:明確にするために、それらを控えめに使用する必要がある2つの主な理由があります:

  1. 必要のない場合にインラインを使用することで、大量のバイナリを簡単に作成できます
  2. コンパイラは、パフォーマンスの観点から何かをインライン化する必要がある場合に、あなたよりもよく知っている傾向があります。

物事をそのままにして、コンパイラに作業を任せてから、インラインが最適なソリューションであるかどうかをプロファイルして把握するのが最善です。もちろん、インライン化するのが理にかなっているものもあります(特に数学的な演算子)が、通常はコンパイラに処理させることがベストプラクティスです。

83
Cody Brocious

更新:konrad.kruczynskiの答え ごとに、4.0までの.NETのバージョンには次のことが当てはまります。

MethodImplAttribute class を使用して、preventメソッドがインライン化されないようにすることができます...

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

...しかし、反対のことをする方法はなく、forceインライン化されます。

50
BACON

2つの別々の概念を混ぜています。関数のインライン化は、セマンティクスに影響を与えないコンパイラーの最適化です。関数は、インライン化されているかどうかにかかわらず同じように動作します。

一方、ラムダ関数は純粋にセマンティックな概念です。言語仕様で定められた動作に従う限り、それらの実装または実行方法に関する要件はありません。 JITコンパイラがそのように感じる場合はインライン化できますが、そうでない場合はインライン化できません。

C#にはインラインキーワードはありません。これは、特にJIT化された言語では通常コンパイラに任せることができる最適化であるためです。 JITコンパイラーはランタイム統計にアクセスできるため、コードを作成するときよりもはるかに効率的にインライン化するものを決定できます。コンパイラーが決定した場合、関数はインライン化され、どちらの方法でも実行できることはありません。 :)

32
jalf

C++の意味でのインライン関数を意味していますか?通常の関数の内容は、自動的にコールサイトにインラインでコピーされますか?最終的な効果は、関数を呼び出すときに実際に関数呼び出しが行われないことです。

例:

inline int Add(int left, int right) { return left + right; }

もしそうなら、いいえ、これに相当するC#はありません。

または、別の関数内で宣言されている関数を意味しますか?そうであれば、C#は匿名メソッドまたはラムダ式を介してこれをサポートします。

例:

static void Example() {
  Func<int,int,int> add = (x,y) => x + y;
  var result = add(4,6);  // 10
}
21
JaredPar

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

の コンパイラJust-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
Joel Coehoorn

はい、まさに、唯一の違いは値を返すという事実です。

単純化(式を使用しない):

List<T>.ForEachはアクションを実行しますが、戻り結果を期待していません。

したがって、Action<T>デリゲートで十分です。

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

と言っているのと同じです:

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

違いは、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);

これがお役に立てば幸いです。

6

「これらのものをそのままにしてコンパイラに作業を任せるのが最善です。」(Cody Brocious)は完全に無意味です。私は20年間高性能のゲームコードをプログラミングしてきましたが、どのコードをインライン化(​​関数)すべきかを知るのに「十分にスマート」なコンパイラにまだ出会っていません。 c#で「インライン」ステートメントを使用すると便利です。真実は、コンパイラが「インライン」ヒントなしで常にインライン化するかどうかを決定するために必要な情報をすべて持っていないことです。関数が小さい(アクセサー)場合は自動的にインライン化される可能性がありますが、数行のコードの場合はどうでしょうか?コンパイラーはそれを知る方法がなく、最適化されたコード(アルゴリズムを超えて)をコンパイラーに任せることはできません。

2
gvick2002

コードを強制的にインライン化したい場合があります。

たとえば、非常に反復的なブロック内で多数の決定が行われる複雑なルーチンがあり、それらの決定によって実行されるアクションが似ているがわずかに異なる場合があります。例えば、複雑な(DB駆動ではない)ソート比較器を考えてみましょう。ソートアルゴリズムは、高速言語の文法的基準と意味的基準に従って単語をソートする場合のように、さまざまな無関係な基準に従って要素をソートします。認識システム。ソースコードの可読性とモジュール性を維持するために、これらのアクションを処理するヘルパー関数を作成する傾向があります。

これらのヘルパー関数はインライン化する必要があることを知っています。これは、人間がコードを理解する必要がない場合にコードを記述する方法だからです。この場合、関数呼び出しのオーバーヘッドがないことを確実に確認したいと思います。

2
developer

この質問はC#に関するものだと思います。ただし、F#を使用して.NETでインライン関数を作成できます。参照: F#での `inline`の使用

0
Goswin

アセンブリが生成される場合は、TargetedPatchingOptOutをご覧ください。これは、ngenがメソッドをインライン化するかどうかを決定するのに役立ちます。 MSDNリファレンス

ただし、命令型コマンドではなく、最適化するための宣言的なヒントにすぎません。

0

いいえ、C#にはそのような構造はありませんが、.NET JITコンパイラーはJIT時にインライン関数呼び出しを行うことを決定できます。しかし、実際にそのような最適化を行っているかどうかはわかりません。
(そうすべきだと思う:-))

0
mmmmmmmm