Plattformsoberoende mål

Modern .NET stöder flera operativsystem och enheter. Det är viktigt att .NET-bibliotek med öppen källkod stöder så många utvecklare som möjligt, oavsett om de skapar en ASP.NET webbplats som finns i Azure eller ett .NET-spel i Unity.

.NET- och .NET Standard-mål

.NET- och .NET Standard-mål är det bästa sättet att lägga till plattformsoberoende stöd i ett .NET-bibliotek.

  • .NET Standard är en specifikation av .NET-API:er som är tillgängliga för alla .NET-implementeringar. Med .NET Standard kan du skapa bibliotek som är begränsade till att använda API:er som finns i en viss version av .NET Standard, vilket innebär att det kan användas av alla plattformar som implementerar den versionen av .NET Standard.
  • .NET 6-8 är implementeringar av .NET. Varje version är en enskild produkt med en enhetlig uppsättning funktioner och API:er som kan användas för Windows-skrivbordsappar och plattformsoberoende konsolappar, molntjänster och webbplatser.

Mer information om hur .NET jämförs med .NET Standard finns i .NET 5 och .NET Standard.

.NET Standard

Om projektet är avsett för .NET eller .NET Standard och kompileras, garanterar det inte att biblioteket körs korrekt på alla plattformar:

  • Plattformsspecifika API:er misslyckas på andra plattformar. Till exempel Microsoft.Win32.Registry kommer att lyckas i Windows och kasta PlatformNotSupportedException när det används på andra operativsystem.
  • API:er kan bete sig annorlunda. Till exempel har reflektions-API:er olika prestandaegenskaper när ett program använder kompilering i förväg på iOS eller UWP.

Dricks

.NET-teamet erbjuder en plattformskompatibilitetsanalys som hjälper dig att identifiera möjliga problem.

✔️ Börja med att inkludera ett netstandard2.0 mål.

De flesta allmänna bibliotek behöver inte API:er utanför .NET Standard 2.0. .NET Standard 2.0 stöds av alla moderna plattformar och är det rekommenderade sättet att stödja flera plattformar med ett mål. Om du inte behöver stöd för .NET Framework kan du även rikta in dig på .NET Standard 2.1.

✔️ Inkludera ett net6.0 mål eller senare om du behöver nya API:er som introduceras i ett modernt .NET.

.NET 6- och senare appar kan använda ett netstandard2.0 mål, så net6.0 det krävs inte. Du bör uttryckligen rikta in net6.0dig på , net7.0eller net8.0 när du vill använda nyare .NET-API:er.

❌ UNDVIK att inkludera ett netstandard1.x mål.

.NET Standard 1.x distribueras som en detaljerad uppsättning NuGet-paket, vilket skapar ett stort paketberoendediagram och resulterar i nedladdning av många paket när du skapar. Moderna .NET-implementeringar stöder .NET Standard 2.0. Du bör bara rikta in dig på .NET Standard 1.x om du specifikt behöver rikta in dig på en äldre plattform.

✔️ Ta med ett netstandard2.0 mål om du behöver ett netstandard1.x mål.

Alla plattformar som stöder .NET Standard 2.0 använder netstandard2.0 målet och drar nytta av att ha ett mindre paketdiagram medan äldre plattformar fortfarande fungerar och återgår till att använda netstandard1.x målet.

❌ Inkludera INTE ett .NET Standard-mål om biblioteket förlitar sig på en plattformsspecifik appmodell.

Ett UWP-kontrollverktygsbibliotek beror till exempel på en appmodell som bara är tillgänglig på UWP. Appmodellspecifika API:er är inte tillgängliga i .NET Standard.

Flera mål

Ibland behöver du komma åt ramverksspecifika API:er från dina bibliotek. Det bästa sättet att anropa ramverksspecifika API:er är att använda multi-targeting, vilket skapar ditt projekt för många .NET-målramverk i stället för bara ett.

För att skydda dina konsumenter från att behöva skapa för enskilda ramverk bör du sträva efter att ha en .NET Standard-utdata plus en eller flera ramverksspecifika utdata. Med flera mål paketeras alla sammansättningar i ett enda NuGet-paket. Konsumenterna kan sedan referera till samma paket och NuGet väljer lämplig implementering. Ditt .NET Standard-bibliotek fungerar som reservbiblioteket som används överallt, med undantag för de fall där Ditt NuGet-paket erbjuder en ramverksspecifik implementering. Med multi-targeting kan du använda villkorlig kompilering i din kod och anropa ramverksspecifika API:er.

NuGet package with multiple assemblies

✔️ ÖVERVÄG att rikta in dig på .NET-implementeringar utöver .NET Standard.

Med .NET-implementeringar kan du anropa plattformsspecifika API:er som ligger utanför .NET Standard.

Ta inte bort stödet för .NET Standard när du gör detta. Kasta i stället från implementeringen och erbjuda funktions-API:er. På så sätt kan biblioteket användas var som helst och har stöd för körningsbelysning av funktioner.

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 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 NET462 || WINDOWS_UWP
            return true;
#else
            return false;
#endif
        }
    }
}

✔️ ÖVERVÄG flera mål även om källkoden är densamma för alla mål, när projektet har biblioteks- eller paketberoenden.

Projektets beroende paket, antingen direkt eller nedströms, kan använda samma kod-API:er när de omsluts i olika versioner av den beroende sammansättningen per målramverk. Genom att lägga till specifika mål ser du till att dina konsumenter inte behöver lägga till eller uppdatera sina omdirigeringar för sammansättningsbindningar.

❌ UNDVIK flera mål och rikta in dig på .NET Standard, om källkoden är densamma för alla mål och projektet inte har några biblioteks- eller paketberoenden.

.NET Standard-sammansättningen används automatiskt av NuGet. Att rikta in sig på *.nupkg enskilda .NET-implementeringar ökar storleken utan fördel.

✔️ ÖVERVÄG att lägga till ett mål för net462 när du erbjuder ett netstandard2.0 mål.

Att använda .NET Standard 2.0 från .NET Framework har vissa problem som har åtgärdats i .NET Framework 4.7.2. Du kan förbättra upplevelsen för utvecklare som fortfarande använder .NET Framework 4.6.2–4.7.1 genom att erbjuda dem en binär fil som är byggd för .NET Framework 4.6.2.

✔️ Distribuera biblioteket med hjälp av ett NuGet-paket.

NuGet väljer det bästa målet för utvecklaren och skyddar dem genom att välja lämplig implementering.

✔️ Använd en projektfils TargetFrameworks egenskap vid flera mål.

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

✔️ ÖVERVÄG att använda MSBuild.Sdk.Extras när du använder flera mål för UWP och Xamarin eftersom det förenklar projektfilen avsevärt.

❌ UNDVIK att ändra sammansättningsnamnet eller använda olika sammansättningsnamn för varje TFM som biblioteket kompilerar. På grund av beroenden mellan bibliotek kan flera mål med olika sammansättningsnamn per TFM bryta paketkonsumenterna. En sammansättning bör ha samma namn för alla TFM:er.

Äldre mål

.NET har stöd för målversioner av .NET Framework som saknar stöd samt plattformar som inte längre används gemensamt. Även om det finns ett värde i att få biblioteket att fungera med så många mål som möjligt, kan det ge betydande omkostnader att behöva kringgå saknade API:er. Med tanke på deras räckvidd och begränsningar är vissa ramverk inte längre värda att rikta in sig på.

❌ Inkludera INTE ett PCL-mål (Portable Class Library). Exempel: portable-net45+win8+wpa81+wp8

.NET Standard är det moderna sättet att stödja plattformsoberoende .NET-bibliotek och ersätter PCL:er.

❌ Inkludera INTE mål för .NET-plattformar som inte längre stöds. Till exempel SL4, WP.