C# は長い歴史を持つ言語であり、その実行基盤である .NET もまた大きな進化を続けてきました。 しかし、C# と .NET の関係は一見分かりにくく、「どの .NET を使えば、どの C# が使えるのか?」という点で混乱しがちです。
ここでは改めて、C# と .NET のバージョンの関係を整理しておきます。
C# と .NET の関係
まず前提として、
- C# : プログラミング言語(文法・書き方)
- .NET : 実行基盤(ランタイム・標準ライブラリ・SDK)
という別の役割を持っています。
つまり、
C# は「何を書くか」 .NET は「それをどう実行するか」
を担当しています。
この2つは密接に関連していますが、同一のものではありません。
ただし、重要なポイントとして 使用できる C# の最大バージョンは、.NET SDK によって決まります。
バージョンに関する基本ルール
ルール①: 使えるC#の最大バージョンは .NET SDK で決まる
例えば、
- .NET 6 → C# 10 まで使用可能
- .NET 8 → C# 12 まで使用可能
となります。
これは、プロジェクトがターゲットとしている .NET SDK が コンパイラの上限(=使えるC#の文法)を決定しているためです。
ルール②: 実際に使うC#のバージョンは固定できる
.csproj に LangVersion を指定することで、
使用するC#のバージョンを明示的に固定することが可能です。
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>7.0</LangVersion>
</PropertyGroup>
この設定の場合、
- .NET 6 + C# 7 → OK
- .NET 6 + C# 11 → NG(SDKの上限を超えるため)
となります。
チーム開発などで「文法レベルを揃えたい」場合に有効です。
ルール③: LangVersion を指定しない場合
LangVersion を省略した場合は、
SDK に対応する最新の安定版 C# が自動的に適用されます。
- .NET 6 → C# 10
- .NET 8 → C# 12
つまり、新しいSDKを使うほど、 デフォルトで新しい言語機能が利用可能になります。
古いC#を使っても .NET の機能は使える?
結論から言うと、使えます。
制限されるのはあくまで「書き方(文法)」であり、 利用可能な .NET の API やランタイム機能ではありません。
例えば、
.NET 6 + C# 7 の組み合わせでも
- .NET 6 の全てのライブラリ機能は使用可能
- ただしコードの書き方は C# 7 相当になる
という状態になります。
つまり、 最新のランタイムの恩恵(性能改善やAPI拡張など)を受けつつ、 あえて古い文法で開発することも可能です。
C# 言語バージョンと .NET 対応表
| C# | .NET | 主な新機能 |
|---|---|---|
| 1.0 | Framework 1.0 / 1.1 | 基本構文, class, interface, properties |
| 2.0 | Framework 2.0 | generics, nullable value types, partial classes |
| 3.0 | Framework 3.5 | LINQ, lambda expressions, expression trees |
| 4.0 | Framework 4.0 | dynamic, named/optional arguments, COM interop |
| 5.0 | Framework 4.5 | async / await, TAP (Task-based), caller info attributes |
| 6.0 | Framework 4.6 | expression-bodied members, null条件演算子, string interpolation |
| 7.0 | Framework 4.7 / Core 2.0 | tuples, pattern matching, out var |
| 7.1 | Core 2.0 | async Main, default literals, inferred tuple names |
| 7.2 | Core 2.0 | ref struct, Span, readonly struct |
| 7.3 | Core 2.1 | unmanaged constraint, fixed improvements, stackalloc init |
| 8.0 | Core 3.0 | nullable reference types, switch expressions, using declarations |
| 9.0 | .NET 5 | record types, init-only setters, top-level statements |
| 10.0 | .NET 6 (LTS) | global using, file-scoped namespace, record struct |
| 11.0 | .NET 7 | required members, list patterns, raw string literals |
| 12.0 | .NET 8 (LTS) | primary constructors, collection expressions, inline arrays |
| 13.0 | .NET 9 | params collections, interceptors (Preview), partial properties |