Condividi tramite


Targeting multipiattaforma

Il moderno .NET supporta diversi sistemi operativi e dispositivi. È importante che le librerie open-source .NET supportino il maggior numero possibile di sviluppatori, sia che stiano creando un sito web ASP.NET ospitato su Azure, sia un gioco .NET in Unity.

Quando si scelgono i framework di destinazione per la libreria, è importante distinguere tra due obiettivi diversi:

  • API e modelli moderni: la libreria si appoggia ai vantaggi delle versioni recenti della piattaforma .NET. Si usano modelli di linguaggio moderni e si supportano modelli di distribuzione avanzati come la compilazione in anticipo nativo in CoreCLR.
  • Larghezza di destinazione: la libreria supporta un'ampia gamma di implementazioni e versioni di .NET per ottimizzare la compatibilità tra diversi scenari utente.

Questi obiettivi non richiedono sempre lo stesso approccio. Se le applicazioni di destinazione usano tutti .NET moderne, le librerie possono essere destinate alle stesse versioni moderne di .NET senza dover usare framework meno recenti.

.NET e .NET Standard obiettivi

.NET e .NET Standard sono il modo migliore per aggiungere supporto multipiattaforma a una libreria .NET.

  • Le versioni da .NET da 5 a 10 sono implementazioni di .NET. Ogni versione è un singolo prodotto con un insieme uniforme di funzionalità e API che possono essere utilizzate per le applicazioni desktop Windows, le console app multipiattaforma, i servizi cloud e i siti web.
  • .NET Standard è una specifica delle API .NET disponibili su tutte le implementazioni di .NET. Puntare a .NET Standard consente di produrre librerie che sono vincolate all'uso di API presenti in una determinata versione di .NET Standard, il che significa che possono essere utilizzate da tutte le piattaforme che implementano quella versione di .NET Standard.

Per ulteriori informazioni su come .NET si confronta con .NET Standard, consulta .NET 5 e .NET Standard.

.NET Standard

Se il tuo progetto è rivolto a .NET o .NET Standard e si compila con successo, non garantisce che la libreria funzionerà correttamente su tutte le piattaforme.

  • Le API specifiche della piattaforma falliranno su altre piattaforme. Ad esempio, Microsoft.Win32.Registry avrà successo su Windows e lancerà PlatformNotSupportedException quando usato su qualsiasi altro sistema operativo.
  • Le API possono comportarsi diversamente. Per esempio, le API di riflessione presentano diverse caratteristiche di prestazioni quando un'applicazione utilizza la compilazione anticipata su iOS o UWP.

Suggerimento

Il team .NET offre un analizzatore di compatibilità della piattaforma per aiutarti a scoprire potenziali problemi.

✔️ Iniziare con l'inclusione di un net8.0 target o successivo per le nuove librerie.

Per le nuove librerie, utilizzare le versioni moderne di .NET (ad esempio .NET 8 o versioni successive) fornisce l'accesso alle API e ai più recenti miglioramenti delle prestazioni, e abilita funzionalità come AOT e ottimizzazione. Le versioni moderne di .NET sono multipiattaforma e offrono un'eccellente compatibilità tra Windows, Linux e macOS.

✔️ Prendere in considerazione l'inclusione di un netstandard2.0 target se è necessaria un'ampia compatibilità o il supporto di .NET Framework.

.NET Standard 2.0 è supportato da .NET Framework 4.6.1+ e da tutte le implementazioni .NET moderne. Includere questa destinazione quando è necessario supportare le applicazioni .NET Framework o quando si compilano librerie per garantire la massima compatibilità tra diversi ecosistemi .NET.

❌ Evitare di includere una netstandard1.x destinazione.

.NET Standard 1.x viene distribuito come un insieme granulare di pacchetti NuGet, il che crea un ampio grafo di dipendenze di pacchetti e comporta il download di molti pacchetti durante la compilazione. Le implementazioni moderne di .NET supportano .NET Standard 2.0. È consigliabile usare .NET Standard 1.x solo se è necessario specificamente usare una piattaforma precedente.

✔️ INCLUDI un target netstandard2.0 se ti serve un target netstandard1.x.

Tutte le piattaforme che supportano .NET Standard 2.0 useranno la netstandard2.0 destinazione e trarranno vantaggio dalla presenza di un grafico di pacchetto più piccolo, mentre le piattaforme meno recenti continueranno a funzionare e eseguiranno il fallback all'uso della netstandard1.x destinazione.

❌ NON includere una destinazione .NET Standard se la libreria si basa su un modello di app specifico della piattaforma.

Ad esempio, una libreria toolkit di controllo UWP dipende da un modello di app che è disponibile solo su UWP. Le API specifiche del modello di applicazione non sono disponibili in .NET Standard.

❌ NON pubblicare per netstandard2.0 se il tuo progetto o le tue dipendenze mirano a più target.

netstandard2.0 non è un runtime e i progetti con più destinazioni forniscono un framework di runtime, una libreria specifica, necessaria quando è in esecuzione in altri framework.

Multi-obiettivo

A volte è necessario accedere alle API specifiche del framework dalle proprie librerie. Il modo migliore per chiamare API specifiche del framework consiste nell'usare multitargeting, che compila il progetto per molti framework di destinazione .NET anziché solo per uno.

Per proteggere i consumer dalla necessità di creare per singoli framework, è necessario cercare di avere un output .NET Standard più uno o più output specifici del framework. Con il multi-target, tutti gli assembly vengono confezionati in un unico pacchetto NuGet. I consumatori possono quindi fare riferimento allo stesso pacchetto e NuGet selezionerà l'implementazione appropriata. La tua libreria .NET Standard funge da libreria di fallback utilizzata ovunque, tranne nei casi in cui il tuo pacchetto NuGet offre un'implementazione specifica per un framework. Il multi-targeting consente di utilizzare la compilazione condizionale nel codice e chiamare le API specifiche del framework.

Pacchetto NuGet con più assembly

✔️ CONSIDERARE il targeting delle implementazioni .NET oltre a .NET Standard.

Il targeting delle implementazioni .NET ti consente di chiamare le API specifiche della piattaforma che sono al di fuori dei confini dello .NET Standard.

Non eliminare il supporto per .NET Standard quando si esegue questa operazione. Invece, escludi dall'implementazione e offri le API di capacità. In questo modo, la libreria può essere utilizzata ovunque e supporta l'attivazione delle funzionalità a runtime.

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
        }
    }
}

✔️ CONSIDERA il multi-targeting anche se il tuo codice sorgente è lo stesso per tutti i target, quando il tuo progetto ha delle dipendenze da librerie o pacchetti.

I pacchetti dipendenti del tuo progetto, siano essi diretti o a valle, potrebbero utilizzare le stesse API del codice, ma avvolti in versioni differenti dell'assembly dipendente per ciascun framework di destinazione. Aggiungere obiettivi specifici garantisce che i vostri consumatori non abbiano bisogno di aggiungere o aggiornare i loro reindirizzamenti di binding dell'assembly.

❌ EVITARE il multitargeting e il targeting di .NET Standard, se il codice sorgente è lo stesso per tutte le destinazioni e il progetto non ha dipendenze di libreria o pacchetto.

L'assembly .NET Standard sarà automaticamente utilizzato da NuGet. Prendere di mira le singole implementazioni .NET aumenta le *.nupkg dimensioni senza alcun vantaggio.

✔️ PRENDERE IN CONSIDERAZIONE l'aggiunta di un obiettivo per net462 anche quando si ha come obiettivo netstandard2.0.

L'utilizzo di .NET Standard 2.0 dal .NET Framework presenta alcuni problemi che sono stati risolti in .NET Framework 4.7.2. Puoi migliorare l'esperienza per gli sviluppatori che utilizzano ancora .NET Framework 4.6.2 - 4.7.1 offrendo loro un binario creato per .NET Framework 4.6.2.

✔️ DO distribuisci la tua libreria utilizzando un pacchetto NuGet.

NuGet selezionerà il miglior obiettivo per lo sviluppatore e li proteggerà dall'avere a scegliere l'implementazione appropriata.

✔️ USARE la proprietà TargetFrameworks di un file di progetto quando si utilizza il multi-targeting.

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

❌ EVITARE di modificare il nome dell'assembly o di usare nomi di assembly diversi per ogni TFM compilato dalla libreria. A causa delle dipendenze tra librerie, il multitargeting con nomi di assembly diversi per TFM può interrompere l'utilizzo dei pacchetti da parte dei clienti. Un'assembly dovrebbe avere lo stesso nome in tutti i TFMs.

Obiettivi più vecchi

.NET supporta il targeting di versioni di .NET Framework non più supportate, così come di piattaforme non più di uso comune. Anche se c'è valore nel far funzionare la libreria su quante più piattaforme possibile, aggirare la mancanza di API può comportare un sovraccarico significativo. Considerando la loro portata e limitazioni, alcuni framework non valgono più la pena di essere presi di mira.

❌ NON includere un obiettivo per una Libreria di Classi Portabile (PCL). Ad esempio: portable-net45+win8+wpa81+wp8.

.NET Standard è il modo moderno per supportare le librerie .NET multipiattaforma e sostituisce gli PCL.

❌ NON includere target per le piattaforme .NET che non sono più supportate. Per esempio, SL4, WP.