O C # 8 oferece suporte ao .NET Framework?

132

Nas configurações do Visual Studio 2019 Advanced Build, C # 8 não parece estar disponível para um projeto .NET Framework, apenas (como na imagem abaixo) para um projeto .NET Core 3.0:

insira a descrição da imagem aqui

O C # 8 oferece suporte ao .NET Framework?

James Harcourt
fonte

Respostas:

240

Sim, C # 8 pode ser usado com o .NET Framework e outros destinos anteriores ao .NET Core 3.0 / .NET Standard 2.1 no Visual Studio 2019 (ou versões anteriores do Visual Studio, se você instalar um pacote Nuget ).

A versão do idioma deve ser definida 8.0no arquivo csproj.

A maioria - mas não todos - os recursos estão disponíveis, seja qual for a estrutura pretendida.


Recursos que funcionam

Os recursos a seguir são apenas alterações de sintaxe; eles funcionam independentemente da estrutura:

Recursos que podem funcionar

Isso requer novos tipos que não estão no .NET Framework. Eles só podem ser usados ​​em conjunto com pacotes Nuget "polyfill" ou arquivos de código:

Membros da interface padrão - não funcionam

Os membros da interface padrão não serão compilados no .NET Framework e nunca funcionarão porque exigem alterações de tempo de execução no CLR. O .NET CLR agora está congelado, pois o .NET Core é o caminho a seguir.

Para obter mais informações sobre o que funciona e o que não funciona, e sobre possíveis polyfills, consulte o artigo de Stuart Lang, C # 8.0 e .NET Standard 2.0 - Doing Unsupported Things .


Código

O projeto C # a seguir direcionado ao .NET Framework 4.8 e usando tipos de referência anuláveis ​​C # 8 é compilado no Visual Studio 16.2.0. Eu o criei escolhendo o modelo .NET Standard Class Library e, em seguida, editando-o para atingir o .NET Framework:

.csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net48</TargetFrameworks>
    <LangVersion>8.0</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

.cs:

namespace ClassLibrary1
{
    public class Class1
    {
        public string? NullableString { get; set; }
    }
}

Em seguida, tentei um projeto WinForms do .NET Framework 4.5.2, usando um .csprojformato legado , e adicionei a mesma propriedade de tipo de referência anulável. Alterei o tipo de idioma na caixa de diálogo de configurações do Visual Studio Advanced Build (desativado em 16.3) para lateste salvei o projeto. Claro que neste ponto não se constrói. Abri o arquivo do projeto em um editor de texto e mudei latestpara previewna configuração de compilação PropertyGroup:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <LangVersion>preview</LangVersion>

Em seguida, habilitei o suporte para tipos de referência anuláveis ​​adicionando <Nullable>enable</Nullable>ao principal PropertyGroup:

<PropertyGroup>
   <Nullable>enable</Nullable>

Eu recarreguei o projeto e ele foi compilado.


Os detalhes sangrentos

Quando esta resposta foi escrita pela primeira vez, o C # 8 estava em uma prévia e muito trabalho de detetive estava envolvido. Deixo essa informação aqui para a posteridade. Sinta-se à vontade para pular se não precisar saber todos os detalhes sangrentos.

A linguagem C # tem sido historicamente neutra em termos de framework - ou seja, capaz de compilar versões mais antigas do Framework - embora alguns recursos tenham exigido novos tipos ou suporte CLR.

A maioria dos entusiastas do C # deve ter lido a entrada do blog Building C # 8.0 de Mads Torgersen, que explica que certos recursos do C # 8 têm dependências de plataforma:

Fluxos, indexadores e intervalos assíncronos contam com novos tipos de estruturas que farão parte do .NET Standard 2.1 ... .NET Core 3.0, assim como Xamarin, Unity e Mono, todos implementarão .NET Standard 2.1, mas .NET Framework 4.8 irá não. Isso significa que os tipos necessários para usar esses recursos não estarão disponíveis no .NET Framework 4.8.

Isso se parece um pouco com Tuplas de Valor que foram introduzidas no C # 7. Esse recurso exigia novos tipos - as ValueTupleestruturas - que não estavam disponíveis nas versões do NET Framework abaixo de 4.7 ou .NET Standard anterior a 2.0. No entanto , C # 7 ainda pode ser usado em versões mais antigas do .NET, sem tuplas de valor ou com eles instalando o pacote System.ValueTuple Nuget . O Visual Studio entendeu isso e estava tudo bem com o mundo.

No entanto, Mads também escreveu:

Por esse motivo, o uso de C # 8.0 só é compatível com plataformas que implementam .NET Standard 2.1.

... que, se verdadeiro, teria descartado o uso de C # 8 com qualquer versão do .NET Framework e, de fato, até mesmo nas bibliotecas .NET Standard 2.0 que só recentemente fomos encorajados a usar como um alvo básico para código de biblioteca. Você nem mesmo seria capaz de usá-lo com versões do .NET Core anteriores a 3.0, pois elas também oferecem suporte apenas para .NET Standard 2.0.

A investigação começou! -

  • Jon Skeet tem uma versão alfa do Noda-Time usando C # 8 pronta para usar, voltada apenas para .NET Standard 2.0. Ele está claramente esperando que o C # 8 / .NET Standard 2.0 ofereça suporte a todas as estruturas da família .NET. (Veja também a postagem do blog de Jon "Primeiros passos com tipos de referência anuláveis" ).

  • Os funcionários da Microsoft têm discutido os tipos de referência anuláveis ​​da interface do usuário do Visual Studio para C # 8 no GitHub e afirmam que eles pretendem oferecer suporte ao legado csproj(formato SDK pré-.NET Core csproj). Essa é uma indicação muito forte de que o C # 8 poderá ser usado com o .NET Framework. [Suspeito que eles vão voltar atrás agora que a lista suspensa da versão de idioma do Visual Studio 2019 foi desativada e .NET foi vinculado ao C # 7.3]

  • Logo após a famosa postagem do blog, um tópico do GitHub discutiu o suporte multiplataforma. Um ponto importante que surgiu foi que o .NET Standard 2.1 incluirá um marcador que indica que as implementações padrão de interfaces são suportadas - o recurso requer uma alteração de CLR que nunca estará disponível para o .NET Framework. Aqui está a parte importante, de Immo Landwerth, gerente de programa da equipe .NET da Microsoft:

    Espera-se que compiladores (como C #) usem a presença desse campo para decidir se permitem ou não implementações de interface padrão. Se o campo estiver presente, espera-se que o tempo de execução seja capaz de carregar e executar o código resultante.

  • Tudo isso indicava que "C # 8.0 só é compatível com plataformas que implementam .NET Standard 2.1" sendo uma simplificação exagerada e que C # 8 oferecerá suporte para .NET Framework, mas, como há tantas incertezas, perguntei no GitHub e HaloFour respondeu:

    IIRC, o único recurso que definitivamente não aparecerá no .NET Framework é o DIM (métodos de interface padrão), pois requer alterações no tempo de execução. Os outros recursos são orientados pela forma de classes que podem nunca ser adicionadas ao .NET Framework, mas podem ser polyfilled por meio de seu próprio código ou NuGet (intervalos, índices, iteradores assíncronos, descarte assíncrono).

  • Victor Derks comentou que "Os novos atributos anuláveis necessários para projetar os casos de uso anuláveis ​​mais complexos estão disponíveis apenas em System.Runtime.dll que vem com .NET Core 3.0 e .NET Standard 2.1 ... [e] incompatível com .NET Framework 4,8 "

  • No entanto, Immo Landwerth comentou que "A grande maioria de nossas APIs não precisa de nenhum atributo personalizado, pois os tipos são totalmente genéricos ou não nulos" no artigo Experimente tipos de referência anuláveis

  • Ben Hall levantou a questão da disponibilidade de atributos anuláveis ​​fora do Core 3.0 no GitHub, com os seguintes comentários dos funcionários da Microsoft sendo dignos de nota:

C # 8 terá suporte total em .net core 3.0 e .net padrão 2.1 apenas. Se você editar manualmente o arquivo de projeto para usar C # 8 com .net core 2.1, você está em um território sem suporte. Alguns recursos do C # 8 funcionarão bem, alguns recursos do C # 8 não funcionarão muito bem (por exemplo, desempenho ruim), alguns recursos do C # 8 funcionarão com hacks extras e alguns recursos do C # 8 não funcionarão de todo. Muito complexo de explicar. Não o bloqueamos ativamente para que os usuários experientes que podem navegar por ele possam fazê-lo. Eu não recomendaria este mix & match incompatível para ser usado amplamente.

(Jan Kotas)

Pessoas como você que estão dispostas a entender - e trabalhar com elas - são livres para usar C # 8. A questão é que nem todos os recursos de linguagem funcionarão em destinos de nível inferior.

(Immo Landwerth)


Visual Studio 2019

Houve uma grande mudança na versão RTM do Visual Studio 2019 versão 16.3 - a versão de lançamento para C # 8.0: a lista suspensa de seleção de idioma foi desabilitada:

insira a descrição da imagem aqui

A justificativa da Microsoft para isso é:

Seguindo em frente, ... cada versão de cada estrutura terá uma única versão com suporte e padrão, e não ofereceremos suporte a versões arbitrárias. Para refletir essa mudança no suporte, este commit desabilita permanentemente a caixa de combinação da versão do idioma e adiciona um link para um documento explicando a mudança.

O documento que se abre é um controle de versão em linguagem C # . Isso lista C # 8.0 como o idioma padrão para .NET Core 3.x SOMENTE. Ele também confirma que cada versão de cada estrutura terá, daqui para frente, uma única versão com suporte e padrão e que o agnosticismo de estrutura da linguagem não pode mais ser confiável.

A versão do idioma ainda pode ser forçada para 8 para projetos .NET Framework, editando o arquivo .csproj.


Caveat emptor

A combinação C # 8 / .NET Framework não é oficialmente suportada pela Microsoft. É, dizem eles, apenas para especialistas.

Stephen Kennedy
fonte
3
Isso deve esclarecer qualquer confusão decorrente do fato de que podemos, se tentarmos, usar alguns recursos do C # 8 fora do padrão 2.1 - github.com/dotnet/corefx/issues/40039
Ben Hall
2
Os novos atributos anuláveis ​​( docs.microsoft.com/en-us/dotnet/csharp/nullable-attributes ) necessários para projetar os casos de uso anuláveis ​​mais complexos estão disponíveis apenas em System.Runtime.dll que acompanha o .NET Core 3.0 e. NET Standard 2.1. Isso torna o \ C # 8.0 anulável incompatível com o NET Framework 4.8
Victor Derks
3
@BenHall Eu adicionei algumas lições de seu problema - muito obrigado por levantar o problema e por postar aqui. Sinta-se à vontade para editar a resposta se estiver de alguma forma incorreta.
Stephen Kennedy
3
O Visual Studio 2019 IntelliSense não oferece suporte a tipos de referência anuláveis ​​quando especificados por meio <Nullable>enable</Nullable>do csproj. Parece funcionar ao usar #nullable enablediretivas. Veja também: github.com/dotnet/project-system/issues/5551
Bouke
3
@odalet Eu não teria escrúpulos em direcionar C # 8 e usar os recursos básicos que não requerem polyfills (já fazem isso), e possivelmente com os polyfills também (não os precisei). Porém, o melhor conselho que posso dar é: em caso de dúvida, não o faça, pelo menos não se o seu trabalho depender disso.
Stephen Kennedy
34

De acordo com esta entrada do blog, a linguagem está realmente ligada à estrutura:

Isso significa que os tipos necessários para usar esses recursos não estarão disponíveis no .NET Framework 4.8. Da mesma forma, as implementações de membros da interface padrão contam com novos aprimoramentos de tempo de execução, e também não faremos isso no .NET Runtime 4.8.

Por esse motivo, o uso de C # 8.0 só é compatível com plataformas que implementam .NET Standard 2.1. A necessidade de manter o tempo de execução estável nos impediu de implementar novos recursos de linguagem nele por mais de uma década. Com a natureza lado a lado e de código aberto dos tempos de execução modernos, sentimos que podemos evoluí-los novamente de forma responsável e fazer o design da linguagem com isso em mente. Scott explicou em sua atualização no .NET Core 3.0 e .NET Framework 4.8 que o .NET Framework verá menos inovação no futuro, em vez de focar na estabilidade e confiabilidade. Considerando isso, achamos que é melhor perder alguns recursos da linguagem do que ninguém os obter.

user1781290
fonte
3
Muitos mais detalhes na outra resposta de Stephen Kennedy. Na verdade, é fácil fazer um subconjunto substancial do C # 8.0 funcionar ao se direcionar ao .NET Framework. Mas algumas partes do C # 8.0 requerem mudanças no tempo de execução que a Microsoft não fará para o "antigo" .NET Framework. E eles parecem estar amarrando a versão do idioma e a versão do .NET mais intimamente.
Jeppe Stig Nielsen
1

C # 8.0 (e superior) é compatível apenas com .NET Core 3.x e versões mais recentes. Muitos dos recursos mais recentes exigem recursos de biblioteca e tempo de execução introduzidos no .NET Core 3.x: controle de versão da linguagem C #

Zdravko Zdravkov
fonte
3
Você viu a resposta marcada como correta de @stephen kennedy acima?
James Harcourt,