C # 8 prend-il en charge le .NET Framework?

131

Dans les paramètres de génération avancée de Visual Studio 2019, C # 8 ne semble pas être disponible pour un projet .NET Framework, uniquement (comme dans l'image ci-dessous) pour un projet .NET Core 3.0:

entrez la description de l'image ici

C # 8 prend-il en charge le .NET Framework?

James Harcourt
la source

Réponses:

238

Oui, C # 8 peut être utilisé avec .NET Framework et d'autres cibles antérieures à .NET Core 3.0 / .NET Standard 2.1 dans Visual Studio 2019 (ou des versions antérieures de Visual Studio si vous installez un package Nuget ).

La version linguistique doit être définie 8.0dans le fichier csproj.

La plupart des fonctionnalités - mais pas toutes - sont disponibles quel que soit le cadre ciblé.


Fonctionnalités qui fonctionnent

Les fonctionnalités suivantes sont des modifications de syntaxe uniquement; ils fonctionnent quel que soit le cadre:

Fonctionnalités qui peuvent être mises en œuvre

Ceux-ci nécessitent de nouveaux types qui ne sont pas dans le .NET Framework. Ils ne peuvent être utilisés qu'avec des packages Nuget "polyfill" ou des fichiers de code:

Membres de l'interface par défaut - ne fonctionnent pas

Les membres de l'interface par défaut ne compileront pas sous .NET Framework et ne fonctionneront jamais car ils nécessitent des modifications d'exécution dans le CLR. Le .NET CLR est maintenant figé car .NET Core est désormais la voie à suivre.

Pour plus d'informations sur ce qui fonctionne et ce qui ne fonctionne pas, et sur les polyfills possibles, consultez l'article de Stuart Lang, C # 8.0 et .NET Standard 2.0 - Faire des choses non prises en charge .


Code

Le projet C # suivant ciblant .NET Framework 4.8 et utilisant des types de référence Nullable C # 8 se compile dans Visual Studio 16.2.0. Je l'ai créé en choisissant le modèle de bibliothèque de classes standard .NET, puis en le modifiant pour cibler .NET Framework à la place:

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

J'ai ensuite essayé un projet WinForms .NET Framework 4.5.2, en utilisant un .csprojformat hérité , et j'ai ajouté la même propriété de type de référence nullable. J'ai changé le type de langue dans la boîte de dialogue des paramètres de Visual Studio Advanced Build (désactivée dans 16.3) latestet enregistré le projet. Bien sûr, à ce stade, il ne se construit pas. J'ai ouvert le fichier de projet dans un éditeur de texte et changé latesten previewdans la configuration de construction PropertyGroup:

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

J'ai ensuite activé la prise en charge des types de référence Nullable en ajoutant <Nullable>enable</Nullable>au principal PropertyGroup:

<PropertyGroup>
   <Nullable>enable</Nullable>

J'ai rechargé le projet, et il se construit.


Les détails sanglants

Lorsque cette réponse a été écrite pour la première fois, C # 8 était en avant-première et beaucoup de travail de détective a été impliqué. Je laisse cette information ici pour la postérité. N'hésitez pas à l'ignorer si vous n'avez pas besoin de connaître tous les détails sanglants.

Le langage C # a toujours été essentiellement indépendant du framework - c'est-à-dire capable de compiler les anciennes versions du Framework - bien que certaines fonctionnalités aient nécessité de nouveaux types ou la prise en charge de CLR.

La plupart des passionnés de C # auront lu l'entrée de blog Building C # 8.0 de Mads Torgersen, qui explique que certaines fonctionnalités de C # 8 ont des dépendances de plate-forme:

Les flux, indexeurs et plages asynchrones reposent tous sur de nouveaux types de framework qui feront partie de .NET Standard 2.1 ... .NET Core 3.0 ainsi que Xamarin, Unity et Mono implémenteront tous .NET Standard 2.1, mais .NET Framework 4.8 ne pas. Cela signifie que les types requis pour utiliser ces fonctionnalités ne seront pas disponibles sur .NET Framework 4.8.

Cela ressemble un peu aux tuples de valeur qui ont été introduits dans C # 7. Cette fonctionnalité nécessitait de nouveaux types - les ValueTuplestructures - qui n'étaient pas disponibles dans les versions NET Framework inférieures à 4.7 ou .NET Standard antérieures à 2.0. Cependant , C # 7 peut toujours être utilisé dans les anciennes versions de .NET, soit sans tuples de valeur, soit avec eux en installant le package System.ValueTuple Nuget . Visual Studio l'a compris et tout allait bien dans le monde.

Cependant, Mads a également écrit:

Pour cette raison, l'utilisation de C # 8.0 n'est prise en charge que sur les plates-formes qui implémentent .NET Standard 2.1.

... qui, s'il était vrai, aurait exclu l'utilisation de C # 8 avec n'importe quelle version de .NET Framework, et même dans les bibliothèques .NET Standard 2.0 que nous avons récemment été encouragés à utiliser comme cible de base pour le code de bibliothèque. Vous ne pourriez même pas l'utiliser avec les versions .NET Core antérieures à 3.0 car elles ne prennent également en charge que .NET Standard 2.0.

L'enquête était ouverte! -

  • Jon Skeet a une version alpha de Noda-Time utilisant C # 8 prête à l'emploi qui cible uniquement .NET Standard 2.0. Il s'attend clairement à ce que C # 8 / .NET Standard 2.0 prenne en charge tous les frameworks de la famille .NET. (Voir aussi l'article de blog de Jon "Premiers pas avec les types de référence Nullable" ).

  • Les employés de Microsoft ont discuté de l'interface utilisateur de Visual Studio pour les types de référence nullable C # 8 sur GitHub , et il est indiqué qu'ils ont l'intention de prendre en charge l'héritage csproj(format pré- .NET Core SDK csproj). C'est une indication très forte que C # 8 sera utilisable avec le .NET Framework. [Je soupçonne qu'ils vont revenir en arrière maintenant que la liste déroulante de la version linguistique de Visual Studio 2019 a été désactivée et que .NET a été lié à C # 7.3]

  • Peu de temps après le célèbre article de blog, un fil de discussion GitHub a discuté du support multiplateforme. Un point important qui a émergé était que .NET Standard 2.1 inclura un marqueur indiquant que les implémentations par défaut des interfaces sont prises en charge - la fonctionnalité nécessite une modification CLR qui ne sera jamais disponible pour le .NET Framework. Voici l'essentiel, de Immo Landwerth, responsable de programme de l'équipe .NET chez Microsoft:

    Les compilateurs (tels que C #) doivent utiliser la présence de ce champ pour décider d'autoriser ou non les implémentations d'interface par défaut. Si le champ est présent, le runtime devrait pouvoir charger et exécuter le code résultant.

  • Tout cela indiquait que "C # 8.0 n'est pris en charge que sur les plates-formes qui implémentent .NET Standard 2.1" étant une simplification excessive, et que C # 8 prendra en charge le .NET Framework mais, comme il y a tellement d'incertitude, j'ai demandé sur GitHub et HaloFour a répondu:

    IIRC, la seule fonctionnalité qui n'apparaîtra certainement pas sur .NET Framework est DIM (méthodes d'interface par défaut) car cela nécessite des modifications d'exécution. Les autres fonctionnalités sont gérées par la forme des classes qui pourraient ne jamais être ajoutées au .NET Framework mais qui peuvent être polyfilled via votre propre code ou NuGet (plages, index, itérateurs asynchrones, élimination asynchrone).

  • Victor Derks a commenté que «Les nouveaux attributs Nullable requis pour concevoir les cas d'utilisation Nullable plus complexes sont uniquement disponibles dans System.Runtime.dll qui est livré avec .NET Core 3.0 et .NET Standard 2.1 ... [et] incompatible avec .NET Framework 4,8 "

  • Cependant, Immo Landwerth a commenté que "La grande majorité de nos API n'avaient pas besoin d'attributs personnalisés car les types sont soit entièrement génériques ou non nuls" dans l'article Essayer les types de référence Nullable

  • Ben Hall a soulevé le problème de la disponibilité des attributs nullables en dehors de Core 3.0 sur GitHub, les commentaires suivants des employés de Microsoft étant à noter:

C # 8 sera entièrement pris en charge sur .net core 3.0 et .net standard 2.1 uniquement. Si vous modifiez manuellement le fichier projet pour utiliser C # 8 avec .net core 2.1, vous vous trouvez dans un territoire non pris en charge. Certaines fonctionnalités C # 8 fonctionneront bien, certaines fonctionnalités C # 8 ne fonctionneront pas très bien (par exemple, de mauvaises performances), certaines fonctionnalités C # 8 fonctionneront avec des hacks supplémentaires et certaines fonctionnalités C # 8 ne fonctionneront pas du tout. Très complexe à expliquer. Nous ne le bloquons pas activement afin que les utilisateurs experts qui peuvent y naviguer puissent le faire. Je ne recommanderais pas que ce mix & match non pris en charge soit largement utilisé.

(Jan Kotas)

Les gens comme vous qui sont prêts à les comprendre - et à les contourner - sont libres d'utiliser C # 8. Le fait est que toutes les fonctionnalités du langage ne fonctionneront pas sur des cibles de bas niveau.

(Immo Landwerth)


Visual Studio 2019

Il y a eu un changement majeur dans la version RTM de Visual Studio 2019 version 16.3 - la version de lancement pour C # 8.0: la liste déroulante de sélection de langue a été désactivée:

entrez la description de l'image ici

La justification de Microsoft à cet égard est:

À l'avenir, ... chaque version de chaque framework aura une seule version prise en charge et par défaut, et nous ne prendrons pas en charge les versions arbitraires. Pour refléter ce changement de prise en charge, ce commit désactive définitivement la liste déroulante de la version linguistique et ajoute un lien vers un document expliquant le changement.

Le document qui s'ouvre est le contrôle de version en langage C # . Cela répertorie C # 8.0 comme langue par défaut pour .NET Core 3.x UNIQUEMENT. Il confirme également que chaque version de chaque framework aura, à l'avenir, une seule version prise en charge et par défaut et que l'agnosticisme du framework ne pourra plus être invoqué.

La version linguistique peut toujours être forcée à 8 pour les projets .NET Framework en modifiant le fichier .csproj.


Caveat emptor

La combinaison C # 8 / .NET Framework n'est pas officiellement prise en charge par Microsoft. C'est, disent-ils, réservé aux experts.

Stephen Kennedy
la source
3
Cela devrait dissiper toute confusion découlant du fait que nous pouvons, si nous essayons, utiliser certaines fonctionnalités C # 8 en dehors de Standard 2.1 - github.com/dotnet/corefx/issues/40039
Ben Hall
2
Les nouveaux attributs Nullable ( docs.microsoft.com/en-us/dotnet/csharp/nullable-attributes ) requis pour concevoir les cas d'utilisation Nullable plus complexes sont uniquement disponibles dans System.Runtime.dll fourni avec .NET Core 3.0 et. NET Standard 2.1. Cela rend nullable \ C # 8.0 incompatible avec NET Framework 4.8
Victor Derks
3
@BenHall J'ai ajouté quelques points à retenir de votre problème - merci beaucoup d'avoir soulevé le problème et d'avoir publié ici. N'hésitez pas à modifier la réponse si elle est incorrecte.
Stephen Kennedy
3
Visual Studio 2019 IntelliSense ne prend pas en charge les types de référence Nullable lorsqu'ils sont spécifiés via <Nullable>enable</Nullable>le csproj. Cela semble fonctionner lors de l'utilisation de #nullable enabledirectives. Voir aussi: github.com/dotnet/project-system/issues/5551
Bouke
3
@odalet Je n'aurais aucun scrupule à viser C # 8 et à utiliser les fonctionnalités de base qui ne nécessitent pas de polyfills (le font déjà), et peut-être aussi avec les polyfills (je n'en ai pas eu besoin). Cependant, le meilleur conseil que je puisse être est: en cas de doute, ne le faites pas, du moins pas si votre travail en dépend.
Stephen Kennedy le
34

Selon cette entrée de blog, la langue est en effet liée au cadre:

Cela signifie que les types requis pour utiliser ces fonctionnalités ne seront pas disponibles sur .NET Framework 4.8. De même, les implémentations des membres d'interface par défaut reposent sur de nouvelles améliorations d'exécution, et nous ne les apporterons pas non plus dans .NET Runtime 4.8.

Pour cette raison, l'utilisation de C # 8.0 n'est prise en charge que sur les plates-formes qui implémentent .NET Standard 2.1. La nécessité de maintenir la stabilité du runtime nous a empêchés d'y implémenter de nouvelles fonctionnalités linguistiques pendant plus d'une décennie. Avec la nature côte à côte et open source des environnements d'exécution modernes, nous pensons que nous pouvons les faire évoluer à nouveau de manière responsable et faire de la conception de langage dans cet esprit. Scott a expliqué dans sa mise à jour sur .NET Core 3.0 et .NET Framework 4.8 que .NET Framework verra moins d'innovation à l'avenir, se concentrant plutôt sur la stabilité et la fiabilité. Compte tenu de cela, nous pensons qu'il vaut mieux qu'il passe à côté de certaines fonctionnalités du langage que que personne ne les obtienne.

user1781290
la source
3
Beaucoup plus de détails dans l'autre réponse de Stephen Kennedy. En fait, il est assez facile de faire fonctionner un sous-ensemble substantiel de C # 8.0 lors du ciblage de .NET Framework. Mais certaines parties de C # 8.0 nécessitent des modifications du runtime que Microsoft ne va pas apporter à «l'ancien» .NET Framework. Et ils semblent lier plus étroitement la version linguistique et la version .NET.
Jeppe Stig Nielsen
1

C # 8.0 (et supérieur) est pris en charge uniquement sur .NET Core 3.x et les versions plus récentes. La plupart des fonctionnalités les plus récentes nécessitent des fonctionnalités de bibliothèque et d'exécution introduites dans .NET Core 3.x: gestion des versions du langage C #

Zdravko Zdravkov
la source
2
Avez-vous vu la réponse marquée comme correcte de @stephen kennedy ci-dessus?
James Harcourt