同じ C# のコードを書いていても、それが動く基盤は「.NET Framework 4.8」と「.NET 10」で大きく異なります。ソースはよく似ていても、ランタイム・配置方法・対応 OS、そして 文字コードの既定の扱い までが別物です。
この記事は、.NET の歴史 ─ Framework から Core、そして統一へ で整理した流れの続きです。歴史編で「なぜ二つの系統に分かれ、なぜ再び一つの .NET に統一されたのか」を追いました。本記事はその 到達点である 4.8 と 10 を、実務上の差として具体化 します。
本記事のバージョン事実は 2026年7月時点 のものです。.NET のバージョンは毎年更新されるため、参照時は Microsoft の一次情報で最新を確認してください。
まず全体像です。両者はコンパイラや言語仕様の多くを共有しますが、実行を支えるランタイムが別系統 です。
| 観点 | .NET Framework 4.8 | .NET 10 |
|---|---|---|
| 系統 | Windows 同梱のレガシー系(4.x 系の最終) | 統一 .NET(旧 .NET Core 系)の現行 LTS |
| 初出/位置づけ | 2019-04(4.8.1 は 2022-08)。新機能開発は事実上終了 | 2025-11 リリース。2026年7月時点の最新 LTS |
| ランタイム | 単一の巨大ランタイム(CLR)を OS が保持 | モジュール化されたランタイム。アプリと同梱可 |
| 対応 OS | Windows 専用 | Windows / Linux / macOS |
| 既定エンコーディング | システムの ANSI コードページ(日本語環境で CP932) | 常に UTF-8(BOM なし) |
重要な前提を一つ。.NET Framework 4.8 は「廃止」されたわけではありません。 新機能開発は 4.8 / 4.8.1 で事実上止まっていますが、Windows に同梱され、セキュリティ更新とサービシングは継続中です。「終わったもの」ではなく「保守フェーズに入ったもの」として扱うのが正確です。一方の .NET 10 は LTS(Long Term Support:長期サポート)として2028年11月までサポートされます。
.NET Framework は、Windows にインストールされた単一のランタイムを全アプリが共有 する設計です。アプリは「マシンに正しいバージョンの .NET Framework が入っている」ことを前提に配置されます。利点は配置物が小さいこと、欠点は 環境に強く依存すること、そして複数バージョンの並行運用がしにくいことです。
.NET(Core 以降)は、必要な機能を NuGet パッケージ単位で組み合わせる モジュール化 された構造を持ちます。これにより、配置方法の選択肢が広がりました。
# 自己完結 + 単一ファイルで発行(例:Windows x64)
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true
この「アプリ側がランタイムを抱えられる」という発想の転換が、環境依存からの解放 と、後述するクロスプラットフォーム対応の土台になっています。
日本語環境の開発者にとって、この違いは「ローカルの Windows(CP932 前提)で書いたコードを、UTF-8 前提の Linux コンテナで動かす」ときの 文字コード事故 として表面化しがちです。この点は6章で扱います。
.NET(Core 以降)は、世代を追うごとに GC・JIT・ライブラリ実装 の最適化を積み重ねてきました。.NET Framework 4.8 は保守フェーズにあり、こうした継続的な性能改善の対象ではありません。おおまかな傾向として、次のような領域が効いています。
Span<T> / Memory<T> を活用した割り当て削減、ホットパスの最適化。具体的な数値(スループット改善率・メモリ削減率)は版ごとに異なります。本文で数字を出す際は、Microsoft の「Performance Improvements in .NET(各版)」ブログを一次情報として、対象バージョンの計測値を確認・引用してください。ここで固定値を書き込むと古びます。
実務上の要点は「新しいアプリほど、コードを変えずにランタイム更新だけで速くなる余地がある」という点です。これは 4.8 に留まる限り得られない利点です。
統一 .NET は Framework の全 API をそのまま引き継いだわけではありません。Windows 密結合の技術や、設計を刷新した領域 は、非対応化・置換されています。移行時に必ず当たる代表例を挙げます。
| .NET Framework の技術 | .NET 10 での扱い | 代替・備考 |
|---|---|---|
| ASP.NET Web Forms | 非対応 | Blazor / ASP.NET Core MVC / Razor Pages へ |
| WCF(サーバー側) | 非対応 | gRPC、ASP.NET Core Web API、CoreWCF(コミュニティ) |
| .NET Remoting | 非対応 | gRPC / HTTP ベースの通信へ |
AppDomain(複数ドメイン) |
実質非対応 | AssemblyLoadContext へ |
| Windows Workflow Foundation | 非対応 | 代替フレームワーク/再設計 |
| WPF / WinForms | 対応(Windows 専用) | クロスプラットフォームにはならない点に注意 |
ポイントは、「非対応=移行できない」ではなく「設計を置き換える必要がある」 ということです。WebForms のようにパラダイムごと変わるものは書き換え、WPF / WinForms のように動くが Windows 専用のままのものは「動くが可搬にはならない」と理解して計画します。
ここが、本シリーズを貫く「文字コード」というテーマの最初の実例です。4.8 と 10 で、既定の文字コードの扱いそのものが変わっています。
Encoding.Default の意味が違うEncoding.Default は同名のプロパティですが、返すエンコーディングが系統によって別物 です。
Encoding.Default は システムの ANSI コードページ。日本語環境では CP932(Windows の Shift_JIS 実装、Windows-31J)。Encoding.Default は 常に UTF-8(BOM なし)。OS のロケールに依存しません。using System.Text;
// .NET Framework 4.8(日本語環境)
Console.WriteLine(Encoding.Default.CodePage); // 932
Console.WriteLine(Encoding.Default.EncodingName); // 日本語 (シフト JIS)
// .NET 10(どの OS・ロケールでも)
Console.WriteLine(Encoding.Default.CodePage); // 65001
Console.WriteLine(Encoding.Default.EncodingName); // Unicode (UTF-8)
同じ Encoding.Default を「システム既定」のつもりで書いたコードが、Framework では CP932、.NET では UTF-8 として動く。これが Windows→Linux 移行時の文字化けの典型的な震源 です。
もう一つの重要な差です。.NET(Core 以降)では、CP932 などのレガシーコードページが標準では使えません。
Encoding.GetEncoding("shift_jis") や Encoding.GetEncoding(932) が 標準で使えました。NotSupportedException になります。使うには System.Text.Encoding.CodePages パッケージ を参照し、CodePagesEncodingProvider を登録 する必要があります。using System.Text;
// .NET(Core 以降)で CP932 等を使う前準備
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// これで初めて取得できる
var sjis = Encoding.GetEncoding("shift_jis"); // CP932
byte[] bytes = sjis.GetBytes("日本語");
csproj 側の参照:
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="..." />
</ItemGroup>
Framework 時代は意識せず使えていた CP932 が、.NET では 明示的なパッケージ参照とプロバイダー登録を経なければ触れない。日本語を扱う開発者にとっては、地味ですが確実に踏むポイントです。
このように、同じ C# コードでも「どの系統で動くか」で文字コードの既定が変わり、CP932 のような日本語レガシーエンコーディングは追加の準備を要求する ── これが、SnowStack.EncodingProbe のような 文字コードの検出・判別ツール が必要になる背景の一つです。手元のバイト列がどのエンコーディングなのかを取り違えると、Encoding.Default の解釈違いと相まって被害が広がります。
環境ごとの文字コード挙動の差を横断的に束ね直し、EncodingProbe がどの問題を解くのかは、シリーズの締めで扱います。 → EncodingProbe から見た .NET / PowerShell の文字コード環境差
配置や依存管理の仕組みも更新されています。移行実務で最初に触るのはここです。
<!-- SDK スタイル csproj(.NET 10) -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
packages.config vs PackageReferencepackages.config:旧来方式。パッケージ一覧を専用ファイルで管理し、依存の推移解決が弱い。.NET Framework の古いプロジェクトに残っています。.NET Framework でも PackageReference は使えるため、移行の第一歩として先に packages.config → PackageReference へ寄せておく と、その後の SDK スタイル化・.NET 化がスムーズになります。
大づかみの判断軸です。
ほぼそのまま持っていけるもの
Span<T> 等を使わない一般的な BCL 利用書き換え・再設計が要るもの
AppDomain 前提の設計 → AssemblyLoadContextEncoding.Default の解釈、CP932 利用箇所の洗い出しとプロバイダー登録進め方の目安
.NET Framework 4.8 と .NET 10 は、同じ C# を書きながら、動く基盤・配置・対応 OS・そして文字コードの既定が異なる 別系統です。4.8 は保守フェーズの安定版、.NET 10 は継続的に進化する現行 LTS ── どちらを選ぶかは「安定した Windows 資産の維持」か「クロスプラットフォームと性能・機能の前進」かで分かれます。
そして本記事で見た Encoding.Default の意味の違い と CP932 利用時のプロバイダー登録 は、シリーズを貫く「文字コード環境差」というテーマの入口です。同じ問題は PowerShell 側(Windows PowerShell 5.1 と PowerShell 7 の既定エンコーディングの差)にも現れ、最終回でまとめて EncodingProbe に接続します。
Encoding.Default / CodePagesEncodingProvider / .NET Framework から .NET への移行