クロス プラットフォーム ターゲット

最新の .NET では、複数のオペレーティング システムとデバイスがサポートされます。 .NET のオープンソース ライブラリでは、開発者が Azure でホストされる ASP.NET Web サイトを構築しているか、Unity で .NET ゲームを構築しているかに関わらず、できるだけ多くの開発者をサポートすることが重要です。

ライブラリのターゲット フレームワークを選択するときは、次の 2 つの異なる目標を区別することが重要です。

  • 最新の API とパターン: ライブラリは、.NET プラットフォームの最新バージョンの利点に傾いています。 最新の言語パターンを使用し、CoreCLR でのネイティブ事前コンパイルなどの高度なデプロイ モデルをサポートします。
  • 幅広いターゲット設定: ライブラリでは、さまざまなユーザー シナリオ間の互換性を最大化するために、さまざまな .NET 実装とバージョンがサポートされています。

これらの目標には、常に同じアプローチが必要なわけではありません。 ターゲット アプリケーションがすべて最新の .NET を使用している場合、ライブラリは、以前のフレームワークをターゲットにしなくても、同じ最新の .NET バージョンをターゲットにすることができます。

.NET および .NET Standard のターゲット

.NET および .NET Standard のターゲットは、.NET ライブラリにクロスプラットフォーム サポートを追加する最善の方法です。

  • .NET バージョン 5 から 10 は.NET の実装です。 各バージョンは、Windows デスクトップ アプリ、クロスプラットフォーム コンソール アプリ、クラウド サービス、Web サイトに使用できる機能と API の統一されたセットを備えた単一の製品です。
  • .NET Standard は、すべての .NET 実装で使用できる .NET API の仕様です。 .NET Standard をターゲットにすることで、特定のバージョンの .NET Standard 内にある API を使用するように制約されるライブラリを作成できます。これは、そのバージョンの .NET Standard を実装するすべてのプラットフォームで使用できることを意味します。

.NET と .NET Standard を比較する方法の詳細については、「.NET 5 と .NET Standard」を参照してください。

プロジェクトが .NET または .NET Standard を対象とし、正常にコンパイルされた場合でも、ライブラリがすべてのプラットフォームで正常に実行されることは保証されません。

  • プラットフォーム固有の API は、他のプラットフォームでは失敗します。 たとえば、Microsoft.Win32.Registry は Windows では成功し、他の OS で使用する場合、PlatformNotSupportedException がスローされます。
  • API の動作はそれぞれ異なる場合があります。 たとえば、アプリケーションが iOS または Android で事前コンパイルを使用する場合、リフレクション API のパフォーマンス特性は異なります。

ヒント

考えられる問題の検出に役立つプラットフォーム互換性アナライザーが .NET チームから提供されます。

✔️ 新しいライブラリには、net8.0 ターゲット以上を含めることから始めてください。

新しいライブラリの場合、最新の .NET (.NET 8 以降など) をターゲットにすると、最新の API とパフォーマンスの向上にアクセスでき、AOT やトリミングなどの機能が有効になります。 最新の .NET バージョンはクロスプラットフォームであり、Windows、Linux、macOS 間で優れた互換性を提供します。

✔️ 広範な互換性または .NET Framework のサポートが必要な場合は、 netstandard2.0 ターゲットを含めるとします。

.NET Standard 2.0 は、.NET Framework 4.6.1 以降およびすべての最新の .NET 実装でサポートされています。 このターゲットは、.NET Framework アプリケーションをサポートする必要がある場合や、異なる .NET エコシステム間の互換性を最大限に高めるためにライブラリを構築する場合に含めます。

ターゲットを❌含めることは避けてください。netstandard1.x

.NET Standard 1.x は、NuGet パッケージの細分化されたセットとして配布されます。これにより、大規模なパッケージ依存関係グラフが作成され、ビルド時に多数のパッケージがダウンロードされることになります。 最新の .NET 実装は .NET Standard 2.0 をサポートしています。 特に古いプラットフォームをターゲットにする必要がある場合は、.NET Standard 1.x のみをターゲットにしてください。

✔️ netstandard2.0 ターゲットを必要とする場合は、netstandard1.x ターゲットを含めてください。

.NET Standard 2.0 をサポートするすべてのプラットフォームでは netstandard2.0 ターゲットを使用し、より小さなパッケージ グラフを作成することで利点が得られますが、古いプラットフォームは引き続き動作し、netstandard1.x ターゲットを使用するようにフォールバックします。

❌ ライブラリがプラットフォーム固有のアプリ モデルに依存している場合は、.NET Standard ターゲットを含めないでください。

たとえば、WinUI コントロール ツールキット ライブラリは、Windowsでのみ使用できるアプリ モデルに依存します。 アプリ モデル固有の API は .NET Standard では使用できません。

❌プロジェクトまたは依存関係が複数のターゲットの場合は、netstandard2.0 に対して発行しないでください。

netstandard2.0 はランタイムではなく、マルチターゲット プロジェクトでは、他のフレームワークで実行するときに必要なランタイム フレームワーク固有のライブラリが提供されます。

マルチターゲット

場合によっては、ご利用のライブラリからフレームワーク固有の API にアクセスする必要があります。 フレームワーク固有の API を呼び出す最善の方法は、1 つだけでなく、多くの .NET ターゲット フレームワークに対するプロジェクトを構築する、マルチ ターゲットを使用することです。

コンシューマーが個々のフレームワークに対して構築しなくても済むように、.NET Standard 出力に加え、1 つ以上のフレームワーク固有の出力が得られるようにします。 マルチターゲットでは、すべてのアセンブリが 1 つの NuGet パッケージ内にパッケージ化されます。 その後、コンシューマーは同じパッケージを参照でき、NuGet は適切な実装を選択します。 .NET Standard ライブラリはフォールバック ライブラリとして機能します。このライブラリは、NuGet パッケージでフレームワーク固有の実装が提供される場合を除き、あらゆる場所で使用されます。 マルチ ターゲットでは、コードで条件付きコンパイルを使用して、フレームワーク固有の API を呼び出すことができます。

たとえば、複数ターゲットの netstandard2.0net8.0 の NuGet パッケージには、ターゲットごとに個別のアセンブリが含まれています。 NuGet では、コンシューマーごとに最適に一致するアセンブリが選択されます。.NET 8 個のアプリケーションが net8.0 アセンブリを使用します。一方、.NET Framework および古い.NET アプリケーションは、netstandard2.0 アセンブリにフォールバックします。

✔️ .NET Standard に加え、.NET 実装をターゲットにすることを検討してください。

.NET 実装をターゲットにすることで、.NET Standard 外にあるプラットフォーム固有の API を呼び出すことができます。

これを行うときに、.NET Standard のサポートを放棄しないでください。 代わりに、実装から分離させて、機能 API を提供します。 この方法で、ライブラリを任意の場所で使用でき、機能の実行時のライトアップがサポートされます。

public static class GpsLocation
{
    // This project uses multi-targeting to expose device-specific APIs to .NET Standard.
    public static async Task<(double latitude, double longitude)> GetCoordinatesAsync()
    {
#if NET462
        return CallDotNetFrameworkApi();
#elif NET8_0_WINDOWS
        return CallWindowsApi();
#else
        throw new PlatformNotSupportedException();
#endif
    }

    // Allows callers to check without having to catch PlatformNotSupportedException
    // or replicating the OS check.
    public static bool IsSupported
    {
        get
        {
#if NET462 || NET8_0_WINDOWS
            return true;
#else
            return false;
#endif
        }
    }
}

✔️ プロジェクトにライブラリまたはパッケージの依存関係がある場合、ソース コードがすべてのターゲットで同じであっても、マルチターゲットを検討します。

プロジェクトの依存パッケージ (直接または下流) は、ターゲット フレームワークごとに異なるバージョンの依存アセンブリ内にラップされながら、同じコード API を使用する場合があります。 特定のターゲットを追加すると、コンシューマーはアセンブリ バインディング リダイレクトを追加または更新する必要がなくなります。

❌ ソース コードがすべてのターゲットに対して同じであり、プロジェクトにライブラリまたはパッケージの依存関係がない場合は、マルチターゲットおよび .NET Standard のターゲット設定を避けてください。

.NET Standard アセンブリは、NuGet によって自動的に使用されます。 個々の .NET 実装をターゲットにすると、*.nupkg サイズが増えるだけで、利点はありません。

✔️ net462も対象としている場合は、netstandard2.0のターゲットを追加することを検討してください。

.NET Framework から .NET Standard 2.0 を使用する場合、いくつかの問題がありますが、.NET Framework 4.7.2 で対処されました。 .NET Framework 4.6.2 から 4.7.1 を引き続き使用している開発者に、.NET Framework 4.6.2 用にビルドされているバイナリを提供することで、その開発者のエクスペリエンスを向上させることができます。

NuGet パッケージを使用してご利用のライブラリの配布を✔️ 実施してください。

NuGet では開発者にとって最適なターゲットが選択され、開発者が適切な実装を選ぶ必要はなくなります。

✔️ マルチターゲットにする場合は、プロジェクト ファイルの TargetFrameworks プロパティを使用してください。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!-- This project will output net8.0 and netstandard2.0 assemblies -->
    <TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>
</Project>

❌ アセンブリ名を変更したり、ライブラリがコンパイルする TFM ごとに異なるアセンブリ名を使用したりしないでください。 ライブラリ間の依存関係により、TFM ごとに異なるアセンブリ名を持つマルチターゲットがパッケージの使用者に影響を与える可能性があります。 アセンブリはすべての TFM で同じ名前である必要があります。

古いターゲット

.NET は、サポート対象外となった .NET Framework のバージョンや、一般的に使用されなくなったプラットフォームをターゲットにすることをサポートします。 できるだけ多くのターゲットでライブラリを動作させる価値はありますが、API の欠落を回避する必要がある場合、オーバーヘッドが大幅に増える可能性があります。 リーチと制限を考慮すると、特定のフレームワークは、ターゲットにする価値がありません。

❌ Portable Class Library (PCL) ターゲットを含めないでください。 たとえば、「 portable-net45+win8+wpa81+wp8 」のように入力します。

.NET Standard は、クロスプラットフォームの .NET ライブラリをサポートする最新の方法であり、PCL に代わるものです。

❌ サポートされなくなった .NET プラットフォームのターゲットを含めないでください。 たとえば、SL4WP のようになります。