跨平台目標設定Cross-platform targeting

新式 .NET 支援多種作業系統與裝置。Modern .NET supports multiple operating systems and devices. .NET 開放原始碼程式庫要儘可能支援許多開發人員,無論是建置裝載於 Azure 的 ASP.NET 網站,還是 Unity 中的 .NET 遊戲,這一點非常重要。It's important for .NET open-source libraries to support as many developers as possible, whether they're building an ASP.NET website hosted in Azure, or a .NET game in Unity.

.NET Standard.NET Standard

.NET Standard 是為 .NET 程式庫新增跨平台支援的最佳方式。.NET Standard is the best way to add cross-platform support to a .NET library. .NET Standard 是在所有 .NET 實作都可以使用的 .NET API 規格。.NET Standard is a specification of .NET APIs that are available on all .NET implementations. 以 .NET Standard 為目標可讓您產生受限於使用特定 .NET Standard 版本中 Api 的程式庫,這表示它可供所有執行該版本 .NET Standard 的平臺使用。Targeting .NET Standard lets you produce libraries that are constrained to use APIs that are in a given version of .NET Standard, which means it's usable by all platforms that implement that version of .NET Standard.

.NET Standard.NET Standard

將目標設為 .NET Standard 並成功地編譯您的專案,並不保證程式庫將可在所有平台上順利執行:Targeting .NET Standard, and successfully compiling your project, doesn't guarantee the library will run successfully on all platforms:

  1. 平台特定 API 將會在其他平台上失敗。Platform-specific APIs will fail on other platforms. 例如,Microsoft.Win32.Registry 會在 Windows 上成功,並在任何其他 OS 上使用時擲回 PlatformNotSupportedExceptionFor example, Microsoft.Win32.Registry will succeed on Windows and throw PlatformNotSupportedException when used on any other OS.
  2. API 的行為會不一樣。APIs can behave differently. 例如,當應用程式在 iOS 或 UWP 上使用預先編譯時,反映 API 具有不同的效能特性。For example, reflection APIs have different performance characteristics when an application uses ahead-of-time compilation on iOS or UWP.

提示

.NET 小組提供了一個 Roslyn 分析器,可協助您找出可能的問題。The .NET team offers a Roslyn analyzer to help you discover possible issues.

✔️ 請務必開始包括 netstandard2.0 目標。✔️ DO start with including a netstandard2.0 target.

大部分的一般用途程式庫應該不需要 .NET Standard 2.0 以外的 API。Most general-purpose libraries should not need APIs outside of .NET Standard 2.0. 所有新式平台都支援 .NET Standard 2.0,而且是以一個目標支援多個平台的建議方法。.NET Standard 2.0 is supported by all modern platforms and is the recommended way to support multiple platforms with one target.

❌避免包含 netstandard1.x 目標。❌ AVOID including a netstandard1.x target.

.NET standard 1.x 是以一組精細的 NuGet 套件形式發佈,它建立了一個大型的套件相依性圖形,並導致開發人員在建置時下載了大量的套件。.NET Standard 1.x is distributed as a granular set of NuGet packages, which creates a large package dependency graph and results in developers downloading a lot of packages when building. 新式 .NET 部署支援 .NET Standard 2.0。Modern .NET implementations support .NET Standard 2.0. 如果您特別需要以較舊的平台為目標,則應僅將目標設為 .NET Standard 1.x。You should only target .NET Standard 1.x if you specifically need to target an older platform.

✔️ 請務必包含 netstandard2.0 目標 (如果您需要 netstandard1.x 目標)。✔️ DO include a netstandard2.0 target if you require a netstandard1.x target.

所有支援 .NET Standard 2.0 的平台都將使用 netstandard2.0 目標,並從較小的套件圖形中受益,而較舊的平台仍會運作,並改為使用 netstandard1.x 目標。All platforms supporting .NET Standard 2.0 will use the netstandard2.0 target and benefit from having a smaller package graph while older platforms will still work and fall back to using the netstandard1.x target.

❌請勿 包含 .NET Standard 目標 (如果程式庫依賴平台特定應用程式模型)。❌ DO NOT include a .NET Standard target if the library relies on a platform-specific app model.

例如,UWP 控制項工具組程式庫相依於只有 UWP 上可用的應用程式模型。For example, a UWP control toolkit library depends on an app model that is only available on UWP. .NET Standard 中將不提供應用程式模型特定 API。App model specific APIs will not be available in .NET Standard.

多目標Multi-targeting

有時您需要從您的程式庫中存取架構特定 API。Sometimes you need to access framework-specific APIs from your libraries. 呼叫架構特定 API 的最佳方法是使用多目標,它為許多 .NET 目標 Framework 建置專案,而不是僅為一個。The best way to call framework-specific APIs is using multi-targeting, which builds your project for many .NET target frameworks rather than for just one.

為了保護您的取用者不必為個別架構建置,您應該努力獲得 .NET Standard 輸出,加上一或多個架構特定輸出。To shield your consumers from having to build for individual frameworks, you should strive to have a .NET Standard output plus one or more framework-specific outputs. 使用多目標時,所有組件都會封裝在單一 NuGet 套件中。With multi-targeting, all assemblies are packaged inside a single NuGet package. 接著,取用者可以參考相同的套件,NuGet 將挑選適當的實作。Consumers can then reference the same package and NuGet will pick the appropriate implementation. 您的 .NET Standard 程式庫會作為在任何地方使用的後援程式庫,但您的 NuGet 套件提供架構特定實作的案例除外。Your .NET Standard library serves as the fallback library that is used everywhere, except for the cases where your NuGet package offers a framework-specific implementation. 多目標可讓您在程式碼中使用條件式編譯,並呼叫架構特定 API。Multi-targeting allows you to use conditional compilation in your code and call framework-specific APIs.

具有多個元件的 NuGet 套件NuGet package with multiple assemblies

✔️ 考慮將 .NET 實作設為目標 (除了 .NET Standard 之外)。✔️ CONSIDER targeting .NET implementations in addition to .NET Standard.

將 .NET 實作設為目標可讓您呼叫 .NET Standard 之外的平台特定 API。Targeting .NET implementations allows you to call platform-specific APIs that are outside of .NET Standard.

執行此動作時,請不要捨棄 .NET Standard 的支援。Do not drop support for .NET Standard when you do this. 相反地,從實作擲回並提供功能API。Instead, throw from the implementation and offer capability APIs. 這樣,您的程式庫便能任何地方使用,並支援執行階段啟動功能。This way, your library can be used anywhere and supports runtime light-up of features.

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 NET461
        return CallDotNetFramworkApi();
#elif WINDOWS_UWP
        return CallUwpApi();
#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 NET461 || WINDOWS_UWP
            return true;
#else
            return false;
#endif
        }
    }
}

❌ 如果您的原始程式碼對所有目標都相同,請避免多目標和目標 .NET Standard。❌ AVOID multi-targeting as well as targeting .NET Standard, if your source code is the same for all targets.

NuGet 將自動使用 .NET Standard 組件。The .NET Standard assembly will automatically be used by NuGet. 將單一 .NET 實作設為目標會增加 *.nupkg 大小,沒有任何好處。Targeting individual .NET implementations increases the *.nupkg size for no benefit.

✔️ 考慮針對 net461 新增目標 (當您提供 netstandard2.0 目標時)。✔️ CONSIDER adding a target for net461 when you're offering a netstandard2.0 target.

使用 .NET Framework 中的 .NET Standard 2.0,會有一些在 .NET Framework 4.7.2 中已經解決的問題。Using .NET Standard 2.0 from .NET Framework has some issues that were addressed in .NET Framework 4.7.2. 您可以透過為仍在 .NET Framework 4.6.1 - 4.7.1 上的開發人員提供針對 .NET Framework 4.6.1 建置的二進位檔,以改善其體驗。You can improve the experience for developers that are still on .NET Framework 4.6.1 - 4.7.1 by offering them a binary that is built for .NET Framework 4.6.1.

✔️ 優先使用 NuGet 套件散發您的程式庫。✔️ DO distribute your library using a NuGet package.

NuGet 將為開發人員選取最佳目標,並讓他們不需要挑選適當的實作。NuGet will select the best target for the developer and shield them having to pick the appropriate implementation.

✔️ 請務必使用專案檔的 TargetFrameworks 屬性 (當使用多目標時)。✔️ DO use a project file's TargetFrameworks property when multi-targeting.

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

✔️ 考慮使用 MSBuild.Sdk.Extras (當針對 UWP 與 Xamarin 進行多目標時) 因為它可以大幅簡化您的專案檔。✔️ CONSIDER using MSBuild.Sdk.Extras when multi-targeting for UWP and Xamarin as it greatly simplifies your project file.

較舊的目標Older targets

.NET 支援的目標版本 .NET Framework 不太支援的目標版本,以及不再常用的平臺。.NET supports targeting versions of .NET Framework that are long out of support as well as platforms that are no longer commonly used. 雖然使您的程式庫在儘可能多的目標上運作是有價值的,但是必須針對 API 遺漏問題找出因應措施會增加重大額外負荷。While there's value in making your library work on as many targets as possible, having to work around missing APIs can add significant overhead. 考慮到其範圍與限制,我們認為特定架構已不再值得設為目標。We believe certain frameworks are no longer worth targeting, considering their reach and limitations.

❌請勿包含可攜式類別庫 (PCL) 目標。❌ DO NOT include a Portable Class Library (PCL) target. 例如: portable-net45+win8+wpa81+wp8For example, portable-net45+win8+wpa81+wp8.

.NET Standard 是支援跨平台 .NET 程式庫並取代 PCL 的新式方法。.NET Standard is the modern way to support cross-platform .NET libraries and replaces PCLs.

❌請勿包含不再支援之 .NET 平台的目標。❌ DO NOT include targets for .NET platforms that are no longer supported. 例如,SL4WPFor example, SL4, WP.