Runtime: Devrait-il y avoir une version .Net Standard 2.0 de Reflection.Emit?

Créé le 27 avr. 2018  ·  58Commentaires  ·  Source: dotnet/runtime

System.Reflection.Emit ne fait pas partie de .Net Standard, mais il existe des packages qui vous permettent de l'utiliser à partir d'une bibliothèque .Net Standard (en particulier, System.Reflection.Emit et System.Reflection.Emit.Lightweight ). Mais ces packages n'ont pas de version .Net Standard 2.0, uniquement les versions .Net Standard 1.x.

Cela a quelques implications:

  • Les bibliothèques .Net Standard 2.0 ne peuvent pas utiliser typeBuilder.CreateType() (même si ce code fonctionne à la fois sur .Net Framework 4.6.1 et .Net Core 2.0) et doivent utiliser typeBuilder.CreateTypeInfo().AsType() place. Il est possible qu'il existe également d'autres API comme celle-ci.
  • Les bibliothèques .Net Standard 2.0 qui souhaitent utiliser Reflection.Emit doivent toujours utiliser les packages .Net Standard 1.x-style System. *.

Ces problèmes seraient résolus si une version .Net Standard 2.0 était ajoutée aux packages Reflection.Emit. Cela vaudrait-il la peine d'être fait?

Bien que ces deux problèmes soient assez petits, je ne suis donc pas sûr de la valeur ajoutée de cela.

area-System.Reflection.Emit question

Commentaire le plus utile

Merci pour les commentaires à tous. Sur la base des commentaires écrasants, nous avons remis en vente la dernière version des packages existants:

https://www.nuget.org/packages/System.Reflection.Emit/4.3.0
https://www.nuget.org/packages/System.Reflection.Emit.Lightweight/4.3.0

Cependant, comme mentionné précédemment dans ce fil, ces packages prétendent être compatibles netstandard1.1, mais c'est un mensonge. Ils ne fonctionneront que sur .NET Core et .NET Framework. Donc, si vous les utilisez à partir d'une bibliothèque netstandard, attendez-vous à ce que cette bibliothèque échoue si elle est exécutée sur une autre implémentation .NET Standard.

Nous n'avons toujours pas de bonne solution pour les supporter sur netstandard2.0 mais les propriétaires ( @AtsushiKan @joshfree) de System.Relfection.Emit vont essayer de trouver la solution à plus long terme.

Tous les 58 commentaires

@ericstj @weshaggard savez-vous si c'est exprès de cette façon, ou un oubli?

C'était intentionnel. Pour les bibliothèques comme celle-ci qui ont un support irrégulier et aucune implémentation portable, nous avons arrêté d'expédier des paquets. L'attente est que vous cibliez un cadre spécifique si vous en avez besoin. Pour certains, nous avons ramené des paquets avec des mines terrestres (jetant des implémentations sur certaines plates-formes). Les gens pourraient proposer que nous le rajoutions, mais celui-ci en particulier a fait l'objet de débats acharnés dans le passé en raison du manque de support sur tous les frameworks .net basés sur AOT. / cc @terrajobst

@ericstj

L'attente est que vous cibliez un cadre spécifique si vous en avez besoin.

Comment suis-je censé en savoir plus? Pour autant que je sache, Reflection.Emit n'est pas signalé par platform-compat. Et quand je google "Reflet Emit .Net Standard", le seul résultat sur la première page indiquant si vous devez l'utiliser de cette façon est un tweet de juillet 2017 par @terrajobst suggérant que vous devriez le faire (peut-être que la situation a changé depuis ?).

Je vais laisser @terrajobst répondre à cela, peut-être qu'il pensait à la fonctionnalité nuget gaurdrails que nous avions dans les packages 1.x et 1.x. Avec celles-ci, nous avions des implémentations irrégulières et une prise en charge du temps de construction pour la messagerie que les choses ne sont pas prises en charge. Je ne me penche pas particulièrement dans un sens ou dans l'autre ici pour expliquer simplement la façon dont les choses fonctionnent en ce moment. Je pense que si nous pouvons obtenir l'approbation des gens sur l'ajout d'un package avec une implémentation de plate-forme non prise en charge, nous pourrions le faire.

FWIW tout ce qui est disponible dans un framework mais qui n'est pas dans netstandard ou dans une bibliothèque / package avec un actif netstandard signifie que vous devez cibler le framework pour l'obtenir. C'est tout ce que je voulais dire avec mon commentaire d'attente.

@ericstj

tout ce qui est disponible dans un framework mais qui n'est pas dans netstandard ou dans une bibliothèque / package avec un actif netstandard signifie que vous devez cibler le framework pour l'obtenir. C'est tout ce que je voulais dire avec mon commentaire d'attente.

Mais ici, le package (avec les actifs .Net Standard 1.x) existe. Je ne pense pas que vous puissiez simplement arrêter de mettre à jour un package et supposer que les gens ne l'utiliseront plus. À tout le moins, vous devriez avoir une documentation expliquant la situation.

Le plus gros problème avec System.Reflection.Emit est que nous n'avons pas de moyen de fournir la bibliothèque de manière standard à cause de TypeInfo (voir https://github.com/dotnet/corefx/issues/14334). Le package existant cible netstandard1.1 mais c'est un mensonge et ne fonctionnera que sur .NET Framework et .NET Core en raison du couplage étroit que nous avons. Nous l'avons piraté pour qu'il fonctionne en jouant des astuces InternalsVisibleTo pour lui donner accès aux constructeurs de TypeInfo, mais c'est cette même astuce qui l'empêche de fonctionner sur une plate-forme générale .NET Standard. Nous avons décidé de ne pas propager davantage l'erreur en piratant netstandard2.0 de la même manière et avons plutôt arrêté de produire le package et l'avons rendu spécifique à la plate-forme.

Merci d'avoir soulevé le problème @svick et nous devrions utiliser ce problème pour documenter le problème avec le package.

Qu'en est-il de la suppression de la liste des packages qui ne sont plus mis à jour sur NuGet afin qu'il soit clair qu'ils ne sont pas recommandés?

C'est une suggestion raisonnable. Je viens de supprimer toutes les versions de https://www.nuget.org/packages/System.Reflection.Emit/ et https://www.nuget.org/packages/System.Reflection.Emit.Lightweight

C'est vraiment nécessaire. Ne pas pouvoir créer et enregistrer des assemblages est actuellement mon plus gros bloqueur dotnet / corefx # 1 pour la mise à jour vers .NET Core, et j'aimerais vraiment que la mise à niveau de cette API très fondamentale devienne une priorité plus élevée que de travailler sur de nouvelles fonctionnalités .

@masonwheeler juste pour appeler, vous pouvez utiliser Reflection.Emit si vous écrivez une application ou une bibliothèque .NET Core, vous ne pouvez tout simplement pas l'utiliser lors de l'écriture de la bibliothèque .NET Standard actuellement.

@weshaggard êtes-vous sûr? Je viens de vérifier le dépôt, et il semble que non seulement AssemblyBuilder.Save n'est pas encore implémenté, mais il n'existe même pas du tout sur Core! (Je me trompe peut-être; je suis sur mon téléphone et l'interface mobile de GitHub n'est pas la meilleure, mais c'est à ça que ça ressemble.)

@masonwheeler vous avez raison de dire que nous ne prenons pas en charge AssemblyBuilder.Save dans .NET Core qui est suivi par un autre problème https://github.com/dotnet/corefx/issues/4491.

Le voilà! Je pensais avoir déjà vu ce problème, mais la recherche n'a révélé que celui-ci. : P

Mais ouais. Sans la possibilité d' émettre réellement vos résultats, vous ne pouvez pas vraiment dire que vous pouvez utiliser Reflection.Emit sur Core. ☹️

@weshaggard avant que le package System.Reflection.Emit.Lightweight ne soit répertorié sur nuget.org, il était possible d'obtenir le package Selenium.WebDriver dans PowerShell 5 (pour .Net Framework) et PowerShell Core 6 (pour .Net Core 2.0) sous Windows 10 à l'aide de la commande suivante: Install-Package Selenium.WebDriver -Destination $ PSScriptRoot -Force -ForceBootstrap

Maintenant, cette commande ne peut pas télécharger toutes les dépendances de package Selenium pour les deux versions de PowerShell. Il échoue car le package System.Reflection.Emit.Lightweight.4.3.0 n'est pas répertorié sur nuget.org.
Erreur: Install-Package: Impossible de trouver les packages dépendants (System.Reflection.Emit.Lightweight)

Pourriez-vous nous dire comment résoudre ce problème?

@SergeyKhutornoy appelez -vous "Install-Package" dans VS à partir de la console du gestionnaire de packages? Si c'est le cas, cela installe correctement le package pour moi. Si vous appelez Install-Package depuis Powershell, il s'agit d'un autre type de gestion de package. En fait, je viens d'essayer cela localement et j'obtiens une erreur différente (Install-Package: Aucune correspondance n'a été trouvée pour les critères de recherche spécifiés et le nom de package `` Selenium.WebDriver ''.) Je ne connais pas ce système de gestion de packages, donc je suis Je ne sais pas comment contourner ce problème. Une chose que vous pouvez essayer est d'installer explicitement System.Reflection.Emit.Lightweight 4.3.0 d'abord, puis de voir si cela fonctionne. Si cela ne fonctionne pas, y a-t-il une raison pour laquelle vous ne pouvez pas utiliser les outils VS ou nuget pour installer le package?

Annuler la liste de ce package est une erreur et ne pas fournir une version .NET Standard 2.0 est une erreur.

Nous sommes sur le point d'expédier une nouvelle version majeure de notre produit, NServiceBus, et nous ciblons netstandard2.0 . Nous avons également une dépendance sur System.Reflection.Emit et System.Reflection.Emit.Lightweight. J'avais initialement l'intention de cibler .NET Framework et .NET Core séparément, mais une conversation Twitter avec @terrajobst combinée à la découverte de ces packages m'ont conduit à changer de plan et à cibler netstandard2.0 place.

Cela ne me dérange pas de ne pas pouvoir autant enregistrer des assemblages dynamiques - je peux toujours tester la logique dans un .NET Framework TFM - mais DynamicMethod est incroyablement utile et très largement utilisé pour générer des thunks de réflexion, des délégués de convertisseur, etc. Les packages. System.Reflection.Emit. * Ont plus de 20 000 000 de téléchargements.

Veuillez ramener un moyen de référencer DynamicMethod dans les bibliothèques netstandard2.0.

Comment utilisons-nous DynamicMethod dans .NET Core maintenant qu'il n'est pas répertorié en tant que package?

@danielcrenna Vous n'avez pas besoin du package pour utiliser DynamicMethod sur .Net Core, car il est intégré. Vous n'aviez besoin du package que pour l'utiliser sur .Net Standard.

Je pourrais construire mon runtime (qui est déjà publié) sur .netstandard 2.0 en utilisant System.Reflection.Emit.Lightweight 4.3 comme j'utilise DynamicMethod. Je vois maintenant que le processus de construction extrait le package du cache hors ligne et non de nuget. ~ Si le cache hors ligne est arrosé, je ne peux pas créer à nouveau le code pour .NETstandard. ~ (Le fait d'arrêter le cache oblige le processus de construction à extraire à nouveau le paquet, car le paquet est toujours là, bien que non répertorié, donc ce n'est pas un showstopper techniquement, mais sémantiquement).

En regardant ici: https://apisof.net/catalog/System.Reflection.Emit.DynamicMethod quelle est la conclusion que je dois tirer? Que c'est dans NS1.6? Ou dans une dimension intermédiaire où les «extensions de plateforme» sont valides?

Donc iow: Lorsque je cible .netstandard2.0 et que j'utilise DynamicMethod, je peux faire une référence à System.Reflection.Emit.Lightweight bien qu'il ne soit pas répertorié et pris en charge dans ns1.6 (?), Mais cela ne semble vraiment pas une responsabilité car je dépend maintenant d'un paquet qui n'est pas répertorié (et je dois alors espérer que les paquets non répertoriés y seront conservés jusqu'à la fin des temps.) Triste chose est: il n'y a pas d'autre alternative que de dépendre d'un paquet non répertorié qui n'est possible que parce qu'un connaît le nom exact.

// @terrajobst

Pour ajouter: EF Core 2.1 a une dépendance sur Castle.Core (https://www.nuget.org/packages/Castle.Core/) pour ses proxies, qui dépend de System.Reflection.Emit.

N'est-il pas sage pour toutes les personnes impliquées d'avoir ce package (et Emit.Lightweight) d'être simplement enrôlé à nouveau?

@FransBouma à proprement parler EF Core Proxies a la dépendance, pas EF Core lui-même. Mais c'est un désordre de toute façon.

En fait, _FirebirdClient_ a une dépendance sur _System.Reflection.Emit_. Et que faire maintenant, non?

Bien qu'il soit compréhensible que les plates-formes AOT complètes ne puissent pas permettre la génération de nouveaux types au moment de l'exécution, il est plus surprenant que nous ne puissions pas prendre en charge System.Reflection.Emit.Lightweight sur ces plates-formes.
LambdaExpression.Compile() fonctionne sur toutes les plateformes même s'il est interprété sur AOT.

Je suis l'auteur de la bibliothèque LightInject DI et j'utilise Reflection.Emit et DynamicMethod pour générer du code au moment de l'exécution. Tout cela était bon jusqu'à ce que ces autres plates-formes commencent à émerger. SilverLight, WinRT, iOS et ainsi de suite. Alors que faire? Ce que j'ai fait, c'est "shim" les DynamicMethod pour que les OpCodes soient traduits en expressions. Il existe une sorte de relation 1-1 entre les Opcodes et les expressions, donc ce n'est pas du tout difficile.

Jetez un œil ici pour la mise en œuvre.
https://github.com/seesharper/LightInject/blob/a01be40607761d9b446dc4acad37d7f717742975/src/LightInject/LightInject.cs#L4483

Notez que je n'implémente pas tous les Opcodes. Seulement ceux dont j'ai besoin.

Mon point est qu'il devrait être possible de le faire pour tous les OpCodes, puis d'activer BEAUCOUP de bibliothèques pour continuer à cibler netstandard2.0. La plupart des bibliothèques qui utilisent Reflection.Emit ne génèrent pas de nouveaux types. Ils génèrent simplement du code via DynamicMethod

Notez également que DynamicProxy, Moq et les autres bibliothèques qui génèrent des types au moment de l'exécution ne peuvent pas cibler netstandard2.0 . Ils doivent être netcoreapp car ils dépendent essentiellement de AssemblyBuilder avec des amis
Donc, en fin de compte, le package System.Reflection.Emit.Lightweight ne peut jamais être entièrement supprimé de NuGet en tant que netstandard2.0 . Ce serait à nouveau l'histoire de LeftPad

Mes deux centimes

Y a-t-il une liste quelque part des TFM qui prennent en charge System.Reflection.Emit ? Je viens d'ajouter des TFM explicites net45 et netcoreapp2.0 à mon projet, mais je suis sûr que j'en manque.

@jbogard Tous les TFM de frameworks complets devraient être bons en plus des TFM de netcoreapp. Est-ce dans AutoMapper?

Cela semble être une décision mal réfléchie et communiquée avec des conséquences de grande portée qui semble avoir été prise avec très peu d'implication de la communauté qu'elle affecte, surprenant étant donné que les packages ont 22 millions de téléchargements. Cela ne justifie-t-il pas une sorte d'analyse de l'impact potentiel sur tout le monde qui en dépend actuellement?

ServiceStack fait référence aux packages Reflection.Emit désormais supprimés dans ServiceStack.Text, qui est le package de dépendance de base utilisé dans chaque package NuGet ServiceStack ainsi que dans plusieurs autres packages NuGet qui l'utilisent comme dépendance. Nous ne fournissons que les versions netstandard2.0 et net45 , forcer le ciblage de la plate-forme .netcore briserait chaque dépendance et chaque projet netstandard2.0 utilisant - c'est-à-dire le cadre cible préféré pour la création de plates-formes multiples builds qui prennent en charge à la fois .NET Framework et .NET Core.

Alors, quelle est la recommandation maintenant pour les packages utilisant Reflection.Emit? Arrêter de publier des builds .NET Standard 2.0 et dire à tout le monde qu'ils ne peuvent plus créer de builds .NET Standard 2.0 pour leurs bibliothèques et projets?

La solution précédente pour utiliser les API .NET Standard qui n'implémentent pas l'API consistait à lever des exceptions d'exécution PlatformNotSupportedException , pourquoi n'est-ce pas exactement la solution ici?

@seesharper oui, j'ai ajouté ceux-ci mais cela pourrait en laisser d'autres. La documentation de l'API en répertorie plus, mais quels autres pourraient manquer? S'agit-il d'une liste complète des TFM possibles prenant en charge l'API? Et, disons, xamarinxboxone ?

J'ai refactoré mon code DynamicMethod / ILGenerator que j'ai utilisé pour émettre des méthodes de réglage pour les propriétés au moment de l'exécution avec une solution Lambda.Compile () de sorte que la dépendance à Reflection.Emit est maintenant partie, mais j'ai dû passer 3-4 heures dessus que j'aurais aimé dépenser pour d'autres choses. Mais hélas, c'est la vie quand les choses «bougent vite et se cassent souvent» je suppose?

Quoi qu'il en soit, ce que je trouve un peu dérangeant, c'est le silence assourdissant du personnel de Microsoft dans ce fil ces dernières semaines. On a l'impression de débattre de choses dans une pièce quand les personnes qui peuvent réellement changer les choses ne sont pas là.

Je suis tout à fait d'accord avec @mythz et d'autres ici, c'est mal communiqué, et avec 22 millions de téléchargements, c'était une décision stupide avec des conséquences de grande portée.

@mythz Je ne sais pas comment vous l'utilisez, mais pour mes affaires, j'ai dû revenir aux indicateurs de fonctionnalité #if pour supprimer les fonctionnalités des plates-formes qui ne prennent pas en charge les types de bâtiments à la volée (dans capable de mapper à une interface et je crée un proxy à la volée).

@jbogard Nous utilisons un indicateur booléen Env.SupportsEmit pour déterminer au moment de l'exécution si la plate-forme prend en charge Reflection.Emit, si c'est le cas, nous l'utilisons, sinon nous revenons aux expressions compilées. Sur cette note, il serait utile s'il y avait un indicateur Platform.SupportsEmit que tout le monde pourrait utiliser pour vérifier si la plate-forme en cours d'exécution prend en charge Reflection.Emit.

La directive #if nécessiterait la création de plusieurs versions de plate-forme, ce qui serait la cause du changement radical pour tous les packages et projets dépendants qui ciblent .netstandard2.0 , car ils nécessitent également des dépendances .netstandard2.0 .

Juste pour une discussion plus approfondie, je voudrais m'assurer que nous sommes tous sur la même longueur d'onde quand il s'agit de la différence entre System.Reflection.Emit et System.Reflection.Emit.Lightweight .

Ce problème aurait dû être divisé en deux problèmes distincts. 😄

  • Devrait-il y avoir une version .Net Standard 2.0 de Reflection.Emit?
  • Devrait-il y avoir une version .Net Standard 2.0 de System.Reflection.Emit.LightWeight?

System.Reflection.Emit

Ce paquet contient les AssemblyBuilder et les classes associées dont nous avons besoin pour générer des assemblys / types au moment de l'exécution.
Le problème avec ce package est qu'il n'aurait jamais dû être placé sur NuGet en tant que package netstandard car la génération de nouveaux types lors de l'exécution ne peut pas être prise en charge sur les plates-formes AOT complètes.
Je suppose que Microsoft a ajouté cela en tant que package netstandard pour faciliter la migration du framework complet vers les bibliothèques .Net Core et netstandard . Avec le recul, ce n'est pas vraiment la meilleure idée.
L'approche «bait and switch» (comprise par 5 personnes dans le monde entier) n'est pas non plus une excellente solution.

System.Reflection.Emit.LightWeight

Ce package contient la DynamicMethod qui permet de compiler dynamiquement du code SANS créer de nouveaux types. La "méthode dynamique" est fondamentalement une méthode statique pour laquelle nous pouvons créer un délégué utilisé pour appeler la méthode.
LambdaExpression.Compile est fondamentalement la même chose et si nous regardons l'implémentation sur le framework complet, nous verrons qu'elle utilise en fait DynamicMethod sous les couvertures.
Le fait est que LambdaExpression.Compile() fonctionne sur toutes les plates-formes en utilisant l'interprétation sur AOT. Pour cette raison, il n'y a aucune raison pour que nous ne puissions pas créer un package System.Reflection.Emit.LightWeight qui est netstandard utilisant la technique que j'ai décrite plus tôt dans ce fil.

Je suppose que la raison du retour en arrière sur ce point maintenant est de s'assurer que la norme donne réellement un sens à l'avenir. Le problème que je vois est que nous pourrions voir des paquets bibliothèque visant netcoreapp au lieu de netstandard et ce serait vraiment mauvais en ce qui concerne l' évolution du concept d'un montant de netstandard .

Ma suggestion est de faire un effort pour publier System.Reflection.Emit.LightWeight comme un vrai paquet netstandard et de continuer à pousser pour netcoreapp quand il s'agit de System.Reflection.Emit .

@seesharper Autant que je sache, Reflection.Emit (y compris Reflection.Emit.Lightweight) est principalement utilisé pour la performance. Mais si vous implémentiez Reflection.Emit.Lightweight à l'aide d'un interpréteur IL, ses performances seraient probablement assez mauvaises. Je ne suis donc pas convaincu que l'effort de prise en charge du mode d'interprétation IL dans Reflection.Emit.Lightweight serait justifié.

Il est également étrange que System.Reflection.Emit.ILGenerator soit toujours répertorié (https://www.nuget.org/packages/System.Reflection.Emit.ILGeneration), car il s'agit d'un package netstandard1.6, mais ILGenerator n'a pas d'implémentation UWP (https://apisof.net/catalog/System.Reflection.Emit.ILGenerator).

Iow: un peu de désordre, non?

@seesharper Bonne suggestion.

@svick Je ne pense pas que ce soit une justification suffisante pour le couper. Les langages spécifiques à un domaine ont besoin d'une capacité pour construire du code au moment de l'exécution. Les DSL apparaissent assez fréquemment dans les projets de grande envergure ( dixième règle de Greenspun ), et il vaut mieux que chaque écrivain n'ait pas à inventer et à écrire son propre interpréteur pour cela (en utilisant une réflexion régulière et Invoke ). S'il s'agit d'un composant standard, au moins les parties "spécifiées de manière informelle et corrigées de bogues" de la règle seraient atténuées. Quant aux performances d'une implémentation de ciblage AOT, il n'est pas nécessaire qu'elle soit un interpréteur IL. Même sur les plates-formes qui ne permettent pas à un processus de créer des pages de mémoire exécutables, on peut compiler des méthodes dynamiques en code threadé comme le font de nombreuses implémentations FORTH, et pour les petites méthodes dynamiques où le "corps de la méthode" tient dans quelques lignes de cache, le la surcharge d'exécution devrait être assez faible.

Le problème avec ce package est qu'il n'aurait jamais dû être placé sur NuGet en tant que package netstandard car la génération de nouveaux types au moment de l'exécution ne peut pas être prise en charge sur les plates-formes AOT complètes.

Être en désaccord. Les principales plates-formes .NET Core et .NET Framework la prennent en charge, simplement parce que les environnements AOT ne devraient pas l'empêcher de pouvoir prendre en charge les principales plates-formes .NET ciblant netstandard2.0 .

Est-ce maintenant devenu la stratégie pour .NET Standard à l'avenir? Les API non prises en charge dans les environnements AOT vont maintenant être supprimées? Il n'y aura donc plus d'exceptions PlatformNotSupportedException , les API vont être tirées au lieu de revenir vers un sous-ensemble PCL? Ou allons-nous être incohérents et réduire de manière sélective la surface de l'API pour certaines fonctionnalités, mais continuer à en ajouter d'autres?

La prise en charge de l'intersection des API du plus petit dénominateur commun était ce que PCL a fait et a abouti à une expérience de développement horrible qui a forcé la technique d'appât et de commutation PCL et de déléguer à plusieurs implémentations spécifiques à la plate-forme, ce qui est tout l'investissement que nous avons jeté lorsque nous sommes passés à. NET Standard.

La meilleure solution était la solution existante (d'autant plus que la supprimer maintenant est un changement perturbateur et révolutionnaire de ses deps transitifs) qui nous permet d'utiliser Reflection. . La suppression de la possibilité d'utiliser Reflection.Emit dans .NET Standard signifie que les bibliothèques qui l'utilisent ne peuvent plus cibler .NET Standard. À quoi bon même si nous ne pouvons pas utiliser les fonctionnalités partagées par .NET Core et .NET Framework dans une abstraction indépendante de la plate-forme? Ce serait simplement ajouter des abstractions / confusion / complexité inutiles à l'écosystème .NET sans aucun avantage.

Merci pour les commentaires à tous. Sur la base des commentaires écrasants, nous avons remis en vente la dernière version des packages existants:

https://www.nuget.org/packages/System.Reflection.Emit/4.3.0
https://www.nuget.org/packages/System.Reflection.Emit.Lightweight/4.3.0

Cependant, comme mentionné précédemment dans ce fil, ces packages prétendent être compatibles netstandard1.1, mais c'est un mensonge. Ils ne fonctionneront que sur .NET Core et .NET Framework. Donc, si vous les utilisez à partir d'une bibliothèque netstandard, attendez-vous à ce que cette bibliothèque échoue si elle est exécutée sur une autre implémentation .NET Standard.

Nous n'avons toujours pas de bonne solution pour les supporter sur netstandard2.0 mais les propriétaires ( @AtsushiKan @joshfree) de System.Relfection.Emit vont essayer de trouver la solution à plus long terme.

@svick

Autant que je sache, Reflection.Emit (y compris Reflection.Emit.Lightweight) est principalement utilisé pour la performance. Mais si vous implémentiez Reflection.Emit.Lightweight à l'aide d'un interpréteur IL, ses performances seraient probablement assez mauvaises. Je ne suis donc pas convaincu que l'effort de prise en charge du mode d'interprétation IL dans Reflection.Emit.Lightweight serait justifié.

Je crois comprendre que LambaExpression.Compile() et son exécution sont interprétés sur les plates-formes AOT et qu'il ne devrait donc pas être pire de le faire pour System.Reflection.Emit.LightWeight .
Il y a beaucoup de bibliothèques utilisant ce package et avoir un "vrai" package netstandard2.0 permettrait soudainement à ces packages de fonctionner sur votre iPhone sans forcer les développeurs de ces packages à réécrire leur code pour correspondre aux différentes plates-formes. Les performances seraient dégradées, mais cela fonctionnerait exactement comme aujourd'hui avec LambdaExpression.Compile()

@mythz

Est-ce maintenant devenu la stratégie pour .NET Standard à l'avenir? Les API non prises en charge dans les environnements AOT vont maintenant être supprimées? Il n'y aura donc plus d'exceptions PlatformNotSupportedException, les API vont être tirées au lieu de revenir vers un sous-ensemble PCL? Ou allons-nous être incohérents et réduire de manière sélective la surface de l'API pour certaines fonctionnalités, mais continuer à en ajouter d'autres?

IMHO, jeter PlatformNotSupportedException n'est qu'une autre manifestation du sous-ensemble d'API que nous avons vu avec PCL. Comme c'est le cas avec System.Reflection.Emit.LightWeight , nous pouvons réellement l'implémenter et il n'y a aucune raison de lancer un PlatformNotSupportedException . Je reconnais cependant qu'il est problématique que des plates-formes moins performantes empêchent la norme d'aller de l'avant. Mais c'est en quelque sorte la nature d'une norme. Lorsque des ajouts sont apportés à la norme, il faut s'assurer que sa mise en œuvre est au moins en quelque sorte possible par les plates-formes mettant en œuvre la norme. Au moins parmi les principaux acteurs et dirait que Xamarin correspond à cette catégorie.

Ce chiffre tel qu'il se présente aujourd'hui est une sorte de mensonge tel que je le vois. Xamarin prétend prendre en charge netstandard , mais ce support est criblé d'exceptions qui pour nous peuvent sembler raisonnables. Pour le novice, ce n'est peut-être pas si facile à comprendre.

image

@weshaggard

Continuer à publier System.Reflection.Emit tant que package netstandard n'est pas une bonne solution à long terme. Il rend à nouveau le standard "faux" et ne devrait être disponible que pour net / netcoreapp. C'est une pilule amère à avaler, croyez-moi je sais. J'ai exactement le même problème avec 'LightInject.Interception' qui est une bibliothèque proxy utilisant System.Reflection.Emit . Mais je préférerais cibler netcoreapp plutôt que de mentir au consommateur sur le fait que cette bibliothèque peut fonctionner partout.

@seesharper

À mon humble avis, lancer PlatformNotSupportedException n'est qu'une autre manifestation du sous-ensemble d'API que nous avons vu avec PCL. Comme c'est le cas avec System.Reflection.Emit.LightWeight, nous pouvons réellement l'implémenter et il n'y a aucune raison de lancer une exception PlatformNotSupportedException.

Ils ne sont pas du tout équivalents. La seule raison pour laquelle .NET Standard est utile est due à sa surface d'API beaucoup plus grande qui nous permet de créer une seule version à exécuter sur plusieurs plates-formes. Les PCL sont beaucoup moins utiles car son sous-ensemble d'intersection d'API réduit a forcé la création de plusieurs versions spécifiques à la plate-forme pour des fonctionnalités non triviales. Leurs capacités ne sont pas équivalentes et les solutions auxquelles elles conduisent sont très différentes en complexité pour les auteurs de bibliothèques et les consommateurs, avec .NET Standard, nous avons une seule version qui s'exécute sur toutes les plates-formes car nous sommes en mesure de vérifier au moment de l'exécution si la plate-forme prend en charge Reflection.Emit, si ce n'est pas le cas, nous revenons aux expressions Lambda et à la réflexion. Si ces API n'étaient pas disponibles pour les bibliothèques .NET Standard, nous ne pourrions pas avoir une seule version et aurions besoin de revenir au développement et à la maintenance de versions non portables spécifiques à la plate-forme.

Continuer à publier System.Reflection.Emit en tant que package netstandard n'est pas une bonne solution à long terme. Il rend à nouveau le standard "faux" et ne devrait être disponible que pour net / netcoreapp.

Forcer la création et la dépendance de builds spécifiques à la plate-forme est un résultat bien pire, en particulier. avec tant de dépendances transitives qui en dépendent déjà. Le principal avantage de .NET Standard est de pouvoir créer des bibliothèques et des projets pour cibler une seule abstraction utile, si nous ne pouvons pas l'utiliser pour accéder aux fonctionnalités grand public disponibles dans .NET Core et .NET Framework, il ne parvient pas à résoudre son utilisation principale. -case et peut aussi bien ne pas exister car il ne fait qu'ajouter plus d'abstractions / confusion à l'écosystème .NET sans aucun avantage par rapport aux PCL.

PCL a déjà essayé de se lier à des abstractions qui n'exposent que l'intersection des fonctionnalités d'API disponibles dans chaque plate-forme, ce à quoi vous demandez de revenir, car vous n'aurez accès qu'aux API disponibles dans chaque plate-forme et par extension ne contiennent que des API. disponible sur la plateforme la plus restreinte.

Avoir une surface d'API plus large dans .NET Standard est beaucoup plus utile et donne aux auteurs de bibliothèques la liberté de pouvoir choisir comment ils souhaitent gérer la prise en charge de différentes plates-formes.Si ces API n'étaient pas disponibles, cette option n'existerait pas, elle n'existerait pas. forcer les versions spécifiques à la plate-forme et forcer toutes ses bibliothèques et projets dépendants à maintenir également les versions spécifiques à la plate-forme, en ajoutant des frictions, de la fragmentation, en réduisant la portabilité et en limitant la prise en charge aux seules plates-formes que les auteurs choisissent de maintenir les versions pour par rapport à toutes les plates-formes prenant en charge .NET Standard qui prennent en charge cette fonctionnalité.

Ce n'est pas seulement une question de préférence, la suppression de la prise en charge des API grand public a un impact perturbateur considérable sur les solutions disponibles, oblige les builds spécifiques à la plate-forme inutiles à avoir un impact sur l'utilité des bibliothèques tout en cassant toutes les bibliothèques .NET Standard et les projets qui les utilisent.

@weshaggard

Nous n'avons toujours pas de bonne solution pour les supporter sur netstandard2.0 mais les propriétaires ( @AtsushiKan @joshfree) de System.Relfection.Emit vont essayer de trouver la solution à plus long terme.

Que diriez-vous de dire aux iDiots et aux monstres de contrôle qui imposent l'AOT uniquement à tous ceux qui utilisent leurs plates-formes dont ils ont besoin pour façonner et corriger leurs mauvaises règles de plate-forme? (Parce que soyons honnêtes, nous savons tous que c'est de cela qu'il s'agit vraiment: quelques mauvais acteurs très spécifiques dans le monde mobile.)

@mythz vous avez absolument raison.

@masonwheeler

Je comprends parfaitement que cacher le package ref emit est frustrant, compte tenu des retombées qu'il a causées. Je comprends également que nous optimisons pour des environnements d'exécution qui ne vous intéressent pas peuvent être bouleversants, en particulier lorsque cela inclut des compromis qui affectent négativement les scénarios qui vous intéressent.

Cela étant dit, j'ai qualifié votre commentaire de "abusif" car il n'est pas constructif. Insulter les gens ne réglera pas ces problèmes. Considérez également que ce n'est pas une politique que nous contrôlons. Le fait que vous ne puissiez pas générer et exécuter du code au moment de l'exécution sur iOS est une décision politique d'Apple. De plus, dans certains cas, ce n'est pas une restriction de politique mais une restriction technologique.

Il y a trois options avec émission de réflexion:

  1. Corrigez les packages actuels et faites-les fonctionner au-dessus de .NET Standard 2.0 . Le problème est une relation d'héritage étrange entre Type et TypeInfo dans .NET Standard 1.x par rapport à 2.0 et ayant des constructeurs non publics. Je peux entrer plus en détail, mais pour rendre le paquet réellement constructible sans restaurer les hacks, c'est un peu délicat, c'est pourquoi nous avons initialement décidé de masquer les paquets.

  2. Ajoutez une émission de réflexion à .NET Standard vNext . Afin de prendre en charge les scénarios AOT uniquement, cela inclurait probablement une API de capacité qui permet aux consommateurs de vérifier si la génération de code est prise en charge ou efficace (c'est-à-dire si nous utilisons une exécution réelle par opposition à l'interprétation).

  3. Ne pas exposer la réflexion émet à .NET Standard et oblige les auteurs de bibliothèques à cibler plusieurs fois . C'était essentiellement le chemin d'origine lorsque nous avons commencé à cacher le paquet.

En ce moment, nous nous penchons vers la première option, mais la deuxième option est également sur la table.

Je suis en faveur de 2. Il est assez omniprésent pour qu'il soit là. Nous avons besoin du contrôle de capacité de toute façon pour d'autres raisons.

Je suis en faveur de 2. Il est assez omniprésent pour qu'il soit là. Nous avons besoin du contrôle de capacité de toute façon pour d'autres raisons.

Moi aussi, mais cela n'aidera personne qui s'appuie actuellement sur .NET Standard 2.0 car cela nécessite une nouvelle version de la norme. Cependant, les API en question existent déjà.

Je pense donc à une solution minimale pour que ces packages fonctionnent tels quels, mais également à .NET Standard 2.0 vNext.

@terrajobst Y a-t-il quelque chose dans l'option 1 qui rend l'option 2 plus difficile à faire? Il me semble qu'obtenir une version des packages qui ciblent netstandard2.0 au lieu d'avoir à extraire le graphique de package netstandard1.1 serait un bon objectif à court terme. Ensuite, pour vNext du standard, il pourrait en faire partie et vous n'auriez plus besoin des packages.

Donc, à moins qu'il y ait une très bonne raison de ne pas le faire, je vote pour 1 et 2.

@bording

On dirait que nous avons publié pratiquement en même temps. J'espère que mon commentaire répond à votre question :-)

Veuillez noter que netstandard2.0 prend en charge la méthode statique System.Reflection.Assembly.Load(byte[] rawAssembly) , qui charge un assembly à partir d'un tableau d'octets d'image binaire. Cela signifie qu'il est possible d'implémenter non pas toutes mais la plupart des API compatibles System.Reflection.Emit sous pure netstandard2.0 .

(Désolé, je ne sais pas combien de plates-formes prennent en charge Assembly.Load sans PNSE)

@GlassGrass à quels frameworks imaginez-vous qu'une implémentation netstandard2.0 s'appliquerait?

Je peux certainement imaginer une implémentation qui écrirait l'IL et produirait un assemblage comme un ILASM piloté par API, mais je ne vois pas de frameworks actuels où je voudrais l'utiliser.

Les frameworks qui ont un JIT (et prennent en charge Assembly.Load) peuvent également prendre en charge Ref.Emit directement et fournir leur implémentation Ref.Emit au lieu d'une version netstandard2.0. Je sais que c'est le cas au moins desktop / .netcore / .netnative. Les deux premiers prennent en charge ref.emit et fournissent une implémentation, le dernier n'en a pas, ni n'a de JIT ni de chargement d'assemblage dynamique.

Je pense que ce serait un projet intéressant pour quelqu'un de jouer dans corefxlab pour écrire quelque chose en plus de System.Reflection.Metadata qui ressemble à Ref.Emit (ou mieux). Je ne sais pas si quelqu'un regarde déjà cela. / cc @nguerrera @tmat

Je pense que ce serait un projet intéressant pour quelqu'un de jouer dans corefxlab pour écrire quelque chose au-dessus de System.Reflection.Metadata qui ressemble à Ref.Emit (ou mieux).

C'est dans mon assiette: (https://github.com/dotnet/corefx/issues/4491 et https://github.com/dotnet/corefx/issues/2800)

https://github.com/dotnet/corefx/issues/2800 viendra en premier car le ref emit stuff est susceptible d'en être une extension. J'ai commencé à prototyper 2800 cette semaine et je continuerai ce travail dans les mois à venir. Je ne le déplace pas vers corefxlab tant que je ne suis pas beaucoup plus avancé. Le flux de travail y est trop inefficace à mon goût.

@AtsushiKan : Heureux de voir qu'il y a encore des travaux en cours sur cette question. Merci d'avoir abordé ce problème.

J'ai déjà mentionné ce qui suit ailleurs: Une chose que System.Reflection.Metadata et Assembly.Load(byte[]) ne peuvent pas faire est l'émission incrémentielle type par type. Vous ne pouvez pas émettre un type, puis un autre ... vous ne pouvez jamais émettre que des assemblys complets, ce qui signifie que ce n'est pas trop utile par exemple pour les bibliothèques moqueuses qui reposent sur la génération de types de proxy dynamiques.

Bien sûr, on ne peut jamais produire des assemblages de type unique, mais cela devient potentiellement inefficace et difficile lorsque l'on rend les composants internes visibles aux assemblys générés dynamiquement via [assembly: InternalsVisibleTo] (une autre chose que les bibliothèques de simulation / test nécessitent souvent). Vous devez être en mesure de donner à plusieurs assemblys dynamiques de type unique la même identité / le même nom fort pour que cela fonctionne. (Le runtime peut déjà le permettre dans la pratique, mais je ne trouve pas de documentation le confirmant officiellement.)

@stakx Vous pouvez émettre System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute à l'assembly dynamique pour lui permettre d'accéder aux membres non publics de l'assembly spécifié, au lieu d'utiliser IVT.

@tmat : C'est intéressant. Cet attribut est-il officiellement documenté quelque part?

C'est dommage que cet attribut spécial ne soit pas officiellement documenté, il est en quelque sorte un peu risqué de l'utiliser en dehors du runtime.

Cela serait-il ajouté à .NET core 3.0 ?

cc @steveharter @joshfree

@karelz https://github.com/dotnet/corefx/issues/30654 suit le travail pour la version 3.0

@joshfree est-ce une dupe ou couvre-t-il plus?

@karelz, il a couvert le problème avec le package Ref.Emit qui était incorrectement supprimé de nuget, puis le package étant réenregistré par @weshaggard. Je pense que ce problème peut maintenant être résolu car le travail restant est suivi avec dotnet / corefx # 30654.

OK, fermant alors :) ... le travail restant est suivi dans dotnet / corefx # 30654 comme mentionné ci-dessus.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

GitAntoinee picture GitAntoinee  ·  3Commentaires

jzabroski picture jzabroski  ·  3Commentaires

noahfalk picture noahfalk  ·  3Commentaires

chunseoklee picture chunseoklee  ·  3Commentaires

omariom picture omariom  ·  3Commentaires