Direcionamento multiplataforma

O .NET moderno dá suporte a vários sistemas operacionais e dispositivos. É importante para as bibliotecas de software livre do .NET dar suporte a desenvolvedores tantos quanto possível, estejam eles criando um site ASP.NET hospedado no Azure ou um jogo .NET no Unity.

Destinos do .NET e do .NET Standard

Destinos do .NET e do .NET standard são a melhor maneira de adicionar suporte multiplataforma a uma biblioteca do .NET.

  • O .NET Standard é uma especificação de APIs .NET disponíveis em todas as implementações do .NET. O direcionamento para .NET Standard permite produzir bibliotecas restritas a usar as APIs que estão em uma determinada versão do .NET Standard, o que significa que ele é usado por todas as plataformas que implementam essa versão do .NET Standard.
  • .NET 6-8 são implementações do .NET. Cada versão é um só produto com um conjunto uniforme de funcionalidades e APIs que podem ser usados para aplicativos da área de trabalho do Windows e aplicativos de console multiplataforma, serviços de nuvem e sites.

Para mais informações sobre como o .NET se compara ao .NET Standard, confira .NET 5 e .NET Standard.

.NET Standard

Se o projeto for direcionado ao .NET ou ao .NET Standard e for compilado com êxito, ele não garantirá que a biblioteca será executada com êxito em todas as plataformas:

  • APIs específicas da plataforma falharão em outras plataformas. Por exemplo, Microsoft.Win32.Registry terá êxito no Windows e gerará PlatformNotSupportedException em qualquer outro sistema operacional.
  • APIs podem se comportar de maneira diferente. Por exemplo, APIs de reflexão têm diferentes características de desempenho quando um aplicativo usa a compilação antecipada em iOS ou UWP.

Dica

A equipe do .NET oferece um Analisador de compatibilidade de plataforma para ajudá-lo a descobrir possíveis problemas.

✔️ FAÇA a inclusão de um destino netstandard2.0.

A maioria das bibliotecas de uso não precisa de APIs fora do .NET Standard 2.0. O .NET standard 2.0 é compatível com todas as plataformas modernas e é a maneira recomendada de dar suporte a várias plataformas com um destino. Se você não precisar dar suporte ao .NET Framework, também poderá direcionar o .NET Standard 2.1.

✔️ INCLUA um destino net6.0 ou posterior se você precisar inserir novas APIs em um .NET moderno.

Os aplicativos .NET 6 ou posteriores podem usar um destino netstandard2.0, portanto, net6.0 não é necessário. Você deve direcionar explicitamente net6.0, net7.0ou net8.0 quando quiser usar APIs .NET mais recentes.

❌ EVITE incluir um destino netstandard1.x.

O .NET standard 1.x é distribuído como um conjunto granular de pacotes do NuGet, que cria um grande grafo de dependência de pacote e resulta em download de muitos pacotes durante o build. Implementações modernas do .NET dão suporte ao .NET Standard 2.0. Você somente deverá direcionar o .NET Standard 1.x se precisar especificamente ter como destino uma plataforma mais antiga.

✔️ FAÇA a inclusão de um destino netstandard2.0 se você precisar de um netstandard1.x destino.

Todas as plataformas que dão suporte a .NET Standard 2.0 usarão o destino netstandard2.0 e se beneficiarão de um grafo de pacote menor, enquanto plataformas mais antigas ainda funcionarão e farão fallback usando o destino netstandard1.x.

❌❌ NÃO inclua um destino do .NET Standard se a biblioteca se basear em um modelo de aplicativo específico da plataforma.

Por exemplo, uma biblioteca do kit de ferramentas de controle UWP depende de um modelo de aplicativo disponível apenas em UWP. APIs específicas do modelo de aplicativo não estão disponíveis no .NET Standard.

Multiplataforma

Às vezes, você precisará acessar APIs específicas da estrutura de suas bibliotecas. A melhor maneira de chamar APIs específicas da estrutura é usar o múltiplos destinos, que compila seu projeto para muitas estruturas de destino do .NET, em vez de apenas uma.

Para proteger seus consumidores de precisarem criar estrutura individuais, você deve se esforçar para ter uma saída do .NET Standard além de uma ou mais saídas específicas da estrutura. Com seus destinos múltiplos, todos os assemblies são empacotados dentro de um único pacote NuGet. Os consumidores podem fazer referência o mesmo pacote e o NuGet escolherá a implementação apropriada. Sua biblioteca .NET Standard serve como a biblioteca de fallback usada em todos os lugares, exceto para casos em que o seu pacote do NuGet oferece uma implementação específica do framework. Ter destinos múltiplos permite que você use a compilação condicional em seu código e chame APIs específicas da estrutura.

NuGet package with multiple assemblies

✔️ CONSIDERE ter como destino implementações do .NET, além do .NET Standard.

Ter como destinos implementações do .NET permite que você chame APIs específicas da plataforma que estão fora do .NET Standard.

Não remova o suporte para o .NET Standard ao fazer isso. Em vez disso, geram da implementação e oferecem APIs de funcionalidade. Dessa forma, sua biblioteca pode ser usada em qualquer lugar e dá suporte à iluminação em runtime de recursos.

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

✔️ CONSIDERE o direcionamento múltiplo, mesmo que seu código-fonte seja o mesmo para todos os destinos, quando seu projeto tiver dependências de biblioteca ou pacote.

Os pacotes dependentes de seu projeto, sejam eles diretos ou downstream, podem usar as mesmas APIs de código, embora estejam encapsulados em diferentes versões do assembly dependente por estrutura de destino. Adicionar destinos específicos garante que seus consumidores não precisem adicionar ou atualizar seus redirecionamentos de vinculação de assembly.

❌ EVITE usar direcionamento múltiplo, bem como o direcionamento do .NET Standard se o código-fonte for o mesmo para todos os destinos e seu projeto não tiver dependências de biblioteca ou pacote.

O assembly .NET padrão será usado automaticamente pelo NuGet. Ter como destino implementações do .NET individuais aumenta o tamanho de *.nupkg sem nenhum benefício.

✔️ CONSIDERE adicionar um destino para net462 quando você está oferecendo um destino netstandard2.0.

Usar o .NET Standard 2.0 do .NET Framework tem alguns problemas que foram resolvidos no .NET Framework 4.7.2. Você pode melhorar a experiência para desenvolvedores que ainda estão no .NET Framework 4.6.2 a 4.7.1 oferecendo a eles um binário compilado para .NET Framework 4.6.2.

✔️ FAZER a distribuição de sua biblioteca usando um pacote NuGet.

O NuGet seleciona o melhor destino para o desenvolvedor e os protege contra a necessidade de escolher a implementação apropriada.

✔️ FAÇA uso da propriedade TargetFrameworks de um arquivo de projeto quando tiver vários destinos.

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

✔️ CONSIDERE usar MSBuild.Sdk.Extras quando ter vários destinos para UWP e Xamarin, o que simplifica muito o seu arquivo de projeto.

❌ EVITE alterar o nome do assembly ou usar nomes de assembly diferentes para cada TFM compilado pela biblioteca. Devido às dependências entre bibliotecas, o multilocatário com nomes diferentes de assembly por TFM pode interromper os consumidores de pacotes. Um assembly deve ter o mesmo nome em todos os TFMs.

Destinos mais antigos

O .NET dá suporte a ter como destino versões do .NET Framework que há muito tempo estão sem suporte, bem como plataformas que não são mais usadas comumente. Embora haja valor fazer sua biblioteca funcionar no máximo possível de destinos, precisar contornar APIs ausentes pode adicionar sobrecarga significativa. Considerando o alcance e as limitações, acreditamos que não vale mais a pena ter determinadas estruturas como destino.

❌ NÃO inclua um destino de PCL (Biblioteca de Classes Portátil). Por exemplo, portable-net45+win8+wpa81+wp8.

O .NET standard é a maneira moderna de dar suporte a bibliotecas do .NET multiplataforma e substitui PCLs.

❌ NÃO inclua destinos para plataformas do .NET que não têm mais suporte. Por exemplo, SL4, WP.