C# は末尾呼び出し再帰を最適化しません。これが F# の目的だからです。
C# コンパイラが末尾呼び出しの最適化を実行できない条件の詳細については、次の記事を参照してください: JIT CLR 末尾呼び出し条件。
C# と F# の間の相互運用性
C# と F# は相互運用性が非常に高く、.NET 共通言語ランタイム (CLR) はこの相互運用性を念頭に置いて設計されているため、各言語はその意図と目的に固有の最適化を使用して設計されています。C# コードから F# コードを呼び出すことがいかに簡単かを示す例については、「C# コードから F# コードを呼び出す」を参照してください。F# コードから C# 関数を呼び出す例については、F# からC# 関数を呼び出すを参照してください。
デリゲートの相互運用性については、次の記事を参照してください: F#、C#、および Visual Basic 間のデリゲートの相互運用性。
C# と F# の理論的および実際的な違い
C# と F# の末尾呼び出し再帰のいくつかの違いを取り上げ、設計の違いを説明する記事を次に示します: C# と F# での末尾呼び出しオペコードの生成。
以下は、C#、F#、および C++\CLI のいくつかの例を含む記事です: C#、F#、および C++\CLIにおける末尾再帰の冒険
主な理論上の違いは、C# はループを使用して設計されているのに対し、F# はラムダ計算の原則に基づいて設計されていることです。ラムダ計算の原理に関する非常に優れた本については、この無料の本を参照してください: Structure and Interpretation of Computer Programs, by Abelson, Sussman, and Sussman .
F# でのテール コールに関する非常に優れた入門記事については、次の記事を参照してください: F# でのテール コールの詳細な紹介。最後に、非末尾再帰と末尾呼び出し再帰 (F# の場合) の違いをカバーする記事を次に示します。