Runtime: Sollte es eine .Net Standard 2.0-Version von Reflection.Emit geben?

Erstellt am 27. Apr. 2018  ·  58Kommentare  ·  Quelle: dotnet/runtime

System.Reflection.Emit ist nicht Teil von .Net Standard, aber es gibt Pakete, mit denen Sie es aus einer .Net Standard-Bibliothek verwenden können (insbesondere System.Reflection.Emit und System.Reflection.Emit.Lightweight ). Diese Pakete haben jedoch keine .Net Standard 2.0-Version, sondern nur .Net Standard 1.x-Versionen.

Dies hat einige Auswirkungen:

  • .Net Standard 2.0-Bibliotheken können nicht typeBuilder.CreateType() (obwohl dieser Code sowohl unter .Net Framework 4.6.1 als auch unter .Net Core 2.0 funktioniert) und müssen stattdessen typeBuilder.CreateTypeInfo().AsType() verwenden. Möglicherweise gibt es auch andere APIs wie diese.
  • .Net Standard 2.0-Bibliotheken, die Reflection.Emit verwenden möchten, müssen weiterhin .Net Standard 1.x-System. * -Pakete verwenden.

Diese Probleme würden behoben, wenn Reflection.Emit-Paketen eine .Net Standard 2.0-Version hinzugefügt würde. Ist das etwas, das es wert wäre, getan zu werden?

Obwohl beide ziemlich kleine Probleme sind, bin ich mir nicht sicher, wie viel Wert dies hinzufügen würde.

area-System.Reflection.Emit question

Hilfreichster Kommentar

Vielen Dank für das Feedback an alle. Aufgrund des überwältigenden Feedbacks haben wir die neueste Version der vorhandenen Pakete erneut aufgelistet:

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

Wie bereits in diesem Thread erwähnt, behaupten diese Pakete, netstandard1.1-kompatibel zu sein, aber das ist eine Lüge. Sie funktionieren nur mit .NET Core und .NET Framework. Wenn Sie sie also aus einer Netstandard-Bibliothek verwenden, ist zu erwarten, dass diese Bibliothek fehlschlägt, wenn sie auf einer anderen .NET Standard-Implementierung ausgeführt wird.

Wir haben immer noch keine großartige Lösung, um diese auf netstandard2.0 zu unterstützen, aber die Eigentümer ( @AtsushiKan @joshfree) von System.Relfection.Emit werden versuchen, die längerfristige Lösung herauszufinden.

Alle 58 Kommentare

@ericstj @weshaggard Weißt du, ob es absichtlich so ist oder ein Versehen?

Es war beabsichtigt. Für Bibliotheken wie diese, die eine gezackte Unterstützung und keine tragbare Implementierung haben, haben wir den Versand von Paketen eingestellt. Die Erwartung ist, dass Sie auf ein bestimmtes Framework abzielen, wenn Sie es benötigen. Für einige haben wir Pakete mit Landminen zurückgebracht (Implementierungen auf einigen Plattformen). Die Leute könnten vorschlagen, dass wir es wieder hinzufügen, aber gerade dieses hat in der Vergangenheit einige heftige Debatten geführt, da alle AOT-basierten .net-Frameworks nicht unterstützt werden. / cc @terrajobst

@ericstj

Die Erwartung ist, dass Sie auf ein bestimmtes Framework abzielen, wenn Sie es benötigen.

Wie soll ich das lernen? Soweit ich das beurteilen kann, wird Reflection.Emit nicht plattformkompatibel gemeldet. Und wenn ich "Reflection Emit .Net Standard" google, ist das einzige Ergebnis auf der ersten Seite, das darüber spricht, ob Sie es so verwenden sollten, ein Tweet von @terrajobst aus dem Juli 2017, der vorschlägt , dass Sie es tun

Ich werde @terrajobst darauf antworten lassen, vielleicht hat er über die Nuget Gaurdrails-Funktion nachgedacht, die wir in den Paketen 1.x und 1.x hatten. Mit diesen hatten wir gezackte Implementierungen und bauten Zeitunterstützung für Messaging auf, dass Dinge nicht unterstützt werden. Ich lehne mich hier nicht besonders in die eine oder andere Richtung, sondern erkläre nur, wie die Dinge im Moment funktionieren. Ich denke, wenn wir uns von Leuten beim Hinzufügen eines Pakets mit einer Plattform, die nicht von der Implementierung unterstützt wird, abmelden können, könnten wir dies tun.

FWIW alles, was in einem Framework verfügbar ist, aber nicht in Netstandard oder in einer Bibliothek / einem Paket mit einem Netstandard-Asset enthalten ist, bedeutet, dass Sie auf das Framework abzielen müssen, um es zu erhalten. Das ist alles, was ich mit meinem Erwartungskommentar gemeint habe.

@ericstj

Alles, was in einem Framework verfügbar ist, aber nicht in Netstandard oder in einer Bibliothek / einem Paket mit einem Netstandard-Asset enthalten ist, bedeutet, dass Sie auf das Framework abzielen müssen, um es zu erhalten. Das ist alles, was ich mit meinem Erwartungskommentar gemeint habe.

Aber hier existiert das Paket (mit .Net Standard 1.x Assets). Ich glaube nicht, dass Sie einfach aufhören können, ein Paket zu aktualisieren, und davon ausgehen können, dass die Leute es nicht mehr verwenden. Zumindest sollten Sie eine Dokumentation haben, die die Situation erklärt.

Das größte Problem mit System.Reflection.Emit ist, dass wir aufgrund von TypeInfo keine Möglichkeit haben, die Bibliothek auf netzstandardisierte Weise bereitzustellen (siehe https://github.com/dotnet/corefx/issues/14334). Das vorhandene Paket zielt auf netstandard1.1 ab, ist jedoch eine Lüge und funktioniert aufgrund der engen Kopplung nur unter .NET Framework und .NET Core. Wir haben es gehackt, indem wir InternalsVisibleTo-Tricks gespielt haben, um Zugriff auf die Konstruktoren von TypeInfo zu erhalten. Dieser Trick führt jedoch dazu, dass es auf einer allgemeinen .NET Standard-Plattform nicht funktioniert. Wir haben beschlossen, den Fehler nicht weiter zu verbreiten, indem wir netstandard2.0 auf die gleiche Weise gehackt haben. Stattdessen haben wir die Produktion des Pakets eingestellt und es plattformspezifisch gemacht.

Vielen Dank, dass Sie das Problem @svick angesprochen haben. Wir sollten dieses Problem verwenden, um die Probleme mit dem Paket zu dokumentieren.

Was ist mit der Aufhebung der Liste der nicht mehr aktualisierten Pakete in NuGet, damit klar ist, dass sie nicht empfohlen werden?

Dies ist sehr wichtig. Nicht in der Lage zu sein, Assemblys zu erstellen und zu speichern, ist derzeit mein größter Blocker für dotnet / corefx # 1 für die Aktualisierung auf .NET Core, und ich würde wirklich gerne sehen, dass die Aktualisierung dieser sehr grundlegenden API eine höhere Priorität hat als die Arbeit an neuen Funktionen .

@masonwheeler Nur um aufzurufen, können Sie Reflection verwenden. Wenn Sie eine .NET Core-App oder -Bibliothek schreiben, können Sie diese beim Schreiben der .NET Standard-Bibliothek derzeit nicht verwenden.

@ Weshaggard bist du sicher? Ich habe gerade das Repo überprüft und es scheint, dass nicht nur AssemblyBuilder.Save nicht implementiert ist, sondern dass es auf Core

@masonwheeler Sie haben Speichern Sie in .NET Core, das von einem anderen Problem verfolgt wird: https://github.com/dotnet/corefx/issues/4491.

Da ist es! Ich dachte, ich hätte dieses Problem schon einmal gesehen, aber die Suche ergab nur dieses. : P.

Aber ja. Ohne die Fähigkeit, Ihre Ergebnisse tatsächlich auszugeben, können Sie nicht wirklich sagen, dass Sie Reflection.Emit on Core verwenden können. ☹️

@weshaggard Bevor das System.Reflection.Emit.Lightweight-Paket auf nuget.org nicht aufgeführt wurde, war es möglich, das Selenium.WebDriver-Paket in PowerShell 5 (für .Net Framework) und PowerShell Core 6 (für .Net Core 2.0) unter Windows 10 abzurufen Verwenden Sie den folgenden Befehl: Install-Package Selenium.WebDriver -Destination $ PSScriptRoot -Force -ForceBootstrap

Dieser Befehl kann jetzt nicht alle Selenium-Paketabhängigkeiten für beide PowerShell-Versionen herunterladen. Es schlägt fehl, weil das Paket System.Reflection.Emit.Lightweight.4.3.0 auf nuget.org nicht aufgeführt ist.
Fehler: Install-Package: Abhängige Pakete können nicht gefunden werden (System.Reflection.Emit.Lightweight)

Können Sie uns einen Rat geben, wie Sie dieses Problem beheben können?

@ SergeyKhutornoy rufen Sie "Install-Package" in VS von der Package Manager-Konsole aus auf? Wenn ja, installiert das das Paket für mich richtig. Wenn Sie Install-Package von Powershell aus aufrufen, ist dies eine andere Art der Paketverwaltung. Ich habe das nur lokal versucht und erhalte einen anderen Fehler (Install-Package: Für die angegebenen Suchkriterien und den Paketnamen 'Selenium.WebDriver' wurde keine Übereinstimmung gefunden.) Ich bin mit diesem Paketverwaltungssystem nicht vertraut, daher bin ich es Ich bin mir nicht sicher, wie ich es umgehen soll. Eine Sache, die Sie versuchen könnten, ist, System.Reflection.Emit.Lightweight 4.3.0 zuerst explizit zu installieren und dann zu prüfen, ob es funktioniert. Wenn dies nicht funktioniert, gibt es einen Grund, warum Sie das Paket nicht mit VS- oder Nuget-Tools installieren können?

Das Auflisten dieses Pakets ist ein Fehler, und das Nicht-Bereitstellen einer .NET Standard 2.0-Version ist ein Fehler.

Wir sind dabei, eine wichtige neue Version unseres Produkts, NServiceBus, zu liefern, und wir zielen auf netstandard2.0 . Wir haben auch eine Abhängigkeit von System.Reflection.Emit und System.Reflection.Emit.Lightweight. Ich hatte ursprünglich vor, .NET Framework und .NET Core separat als Ziel zu verwenden, aber eine Twitter-Konversation mit @terrajobst in Kombination mit der Entdeckung dieser Pakete führte dazu, dass ich Pläne änderte und stattdessen netstandard2.0 als Ziel hatte.

Es macht mir nichts aus, dynamische Assemblys nicht so oft speichern zu können - ich kann die Logik immer in einem .NET Framework TFM testen -, aber DynamicMethod ist unglaublich nützlich und wird häufig verwendet, um Reflection Thunks, Konverterdelegierte usw. Zu generieren . System.Reflection.Emit. * -Pakete haben mehr als 20.000.000 Downloads.

Bitte bringen Sie eine Möglichkeit zurück, auf DynamicMethod in netstandard2.0-Bibliotheken zu verweisen.

Wie verwenden wir DynamicMethod in .NET Core, nachdem es nicht als Paket aufgeführt ist?

@danielcrenna Sie benötigen das Paket nicht, um DynamicMethod auf .Net Core zu verwenden, da es integriert ist. Sie brauchten das Paket nur, um es in .Net Standard zu verwenden.

Ich könnte meine Laufzeit (die bereits veröffentlicht ist) auf .netstandard 2.0 mit System.Reflection.Emit.Lightweight 4.3 erstellen, wenn ich DynamicMethod verwende. Ich sehe jetzt, dass der Erstellungsprozess das Paket aus dem Offline-Cache und nicht aus dem Nuget zieht. ~ Wenn der Offline-Cache abgespritzt ist, kann ich den Code für .NETstandard nicht erneut erstellen. ~ (Durch das Verschließen des Caches wird der Erstellungsprozess das Paket erneut abrufen, da das Paket noch vorhanden ist, obwohl es nicht aufgeführt ist, sodass es kein Showstopper ist technisch. Es ist jedoch semantisch).

Suchen Sie hier: https://apisof.net/catalog/System.Reflection.Emit.DynamicMethod Was ist die Schlussfolgerung, die ich ziehen muss? Dass es in NS1.6 ist? Oder in einer Zwischendimension, in der "Plattformerweiterungen" gültig sind?

Also iow: Wenn ich auf .netstandard2.0 ziele und DynamicMethod verwende, kann ich auf System.Reflection.Emit.Lightweight verweisen, obwohl es nicht aufgeführt ist und in ns1.6 (?) Unterstützt wird, aber das fühlt sich wirklich falsch an: es fühlt sich so an Eine Haftung, da ich jetzt von einem Paket abhängig bin, das nicht gelistet ist (und ich muss dann hoffen, dass nicht gelistete Pakete bis zum Ende der Zeit dort aufbewahrt werden). Traurige Sache ist: Es gibt keine andere Alternative als die Abhängigkeit von einem nicht gelisteten Paket, das nur möglich ist, weil eines kennt den genauen Namen.

// @terrajobst

Hinzufügen: EF Core 2.1 ist für seine Proxys von Castle.Core (https://www.nuget.org/packages/Castle.Core/) abhängig, was von System.Reflection.Emit abhängt.

Ist es nicht für alle Beteiligten ratsam, dieses Paket (und Emit.Lightweight) einfach wieder zu registrieren?

@FransBouma streng genommen hat EF Core Proxies die Abhängigkeit, nicht EF Core selbst. Aber es ist trotzdem ein Chaos.

Tatsächlich ist _FirebirdClient_ von _System.Reflection.Emit_ abhängig. Und was soll ich jetzt tun?

Es ist zwar verständlich, dass auf vollständigen AOT-Plattformen zur Laufzeit keine neuen Typen generiert werden können, es ist jedoch eher überraschend, dass wir auf diesen Plattformen System.Reflection.Emit.Lightweight nicht unterstützen können.
LambdaExpression.Compile() funktioniert auf allen Plattformen, auch wenn es auf AOT interpretiert wird.

Ich bin der Autor der LightInject DI-Bibliothek und verwende Reflection.Emit und DynamicMethod , um zur Laufzeit Code zu generieren. Das war alles gut, bis diese anderen Plattformen auftauchten. SilverLight, WinRT, iOS und so weiter. Was tun? Was ich getan habe, war, die DynamicMethod zu "shimen", damit OpCodes in Ausdrücke übersetzt werden. Es gibt eine Art 1-1-Beziehung zwischen Opcodes und Ausdrücken, so dass es gar nicht so schwer ist.

Schauen Sie sich hier die Implementierung an.
https://github.com/seesharper/LightInject/blob/a01be40607761d9b446dc4acad37d7f717742975/src/LightInject/LightInject.cs#L4483

Beachten Sie, dass ich nicht alle Opcodes implementiere. Nur die, die ich brauche.

Mein Punkt ist, dass es möglich sein sollte, dies für alle OpCodes zu tun und dann zu ermöglichen, dass VIELE Bibliotheken weiterhin auf netstandard2.0 abzielen. Die meisten Bibliotheken, die Reflection.Emit verwenden, generieren keine neuen Typen. Sie generieren einfach Code über die DynamicMethod

Beachten Sie auch, dass DynamicProxy, Moq und andere Bibliotheken, die zur Laufzeit Typen generieren, nicht auf netstandard2.0 abzielen können. Sie müssen netcoreapp da sie sich im Grunde auf AssemblyBuilder mit Freunden verlassen
Unter dem Strich kann das System.Reflection.Emit.Lightweight -Paket niemals vollständig als netstandard2.0 aus NuGet entfernt werden. Das wäre wieder die LeftPad-Geschichte

Meine zwei Cent

Gibt es irgendwo eine Liste der TFMs, die System.Reflection.Emit ? Ich habe meinem Projekt gerade explizite TFMs net45 und netcoreapp2.0 hinzugefügt, aber ich bin sicher, dass mir einige fehlen.

@jbogard Alle

Dies scheint eine schlecht durchdachte und kommunizierte Entscheidung mit weitreichenden Konsequenzen zu sein, die offenbar mit sehr geringer Beteiligung der betroffenen Community getroffen wurde. Dies ist überraschend, da die Pakete 22 Millionen Downloads haben. Ist das nicht eine Art Analyse der möglichen Auswirkungen auf alle, die derzeit davon abhängig sind?

ServiceStack verweist auf die jetzt aufgelisteten Reflection.Emit-Pakete in ServiceStack.Text. Dies ist das Basisabhängigkeitspaket, das in jedem ServiceStack NuGet-Paket sowie in mehreren anderen NuGet-Paketen verwendet wird, die es als Abhängigkeit verwenden. Wir bieten nur Builds für netstandard2.0 und net45 an. Wenn Sie die Targeting-.netcore-Plattform erzwingen , wird jede einzelne Abhängigkeit und jedes netstandard2.0 -Projekt, das sie verwendet, aufgehoben - dh das bevorzugte Ziel-Framework für die Erstellung plattformübergreifender Builds, die sowohl .NET Framework als auch .NET Core unterstützen.

Was ist nun die Empfehlung für Pakete mit Reflection.Emit? Beenden Sie die Veröffentlichung von .NET Standard 2.0-Builds und teilen Sie allen mit, dass sie keine .NET Standard 2.0-Builds mehr für ihre Bibliotheken und Projekte erstellen können.

Die vorherige Lösung für die Verwendung von .NET-Standard-APIs, die die API nicht implementieren, bestand darin, PlatformNotSupportedException Laufzeitausnahmen auszulösen. Warum genau ist das hier nicht die Lösung?

@seesharper ja, ich habe diese hinzugefügt, aber das könnte andere API-Dokumenten ist mehr aufgeführt, aber welche anderen fehlen möglicherweise? Ist das eine umfassende Liste möglicher TFMs, die die API unterstützen? Was ist zum Beispiel mit xamarinxboxone ?

Ich habe meinen DynamicMethod / ILGenerator-Code überarbeitet, mit dem ich zur Laufzeit Setter-Methoden für Eigenschaften mit einer Lambda.Compile () -Lösung ausgegeben habe, sodass die Abhängigkeit von Reflection.Emit jetzt weg ist. Ich musste jedoch 3-4 Stunden damit verbringen was ich gerne für andere Dinge ausgegeben hätte. Aber leider ist das das Leben, in dem sich die Dinge schnell bewegen und oft brechen, denke ich?

Was mich jedenfalls etwas beunruhigt, ist die ohrenbetäubende Stille der Microsoft-Mitarbeiter in diesem Thread in den letzten Wochen. Es fühlt sich an, als würde man in einem Raum darüber diskutieren, wenn die Leute, die tatsächlich etwas ändern können, nicht da sind.

Ich stimme @mythz und anderen hier 22 Millionen Downloads war dies eine dumme Entscheidung mit weitreichenden Konsequenzen.

@mythz Ich weiß nicht, wie Sie es verwenden, aber für meine Inhalte musste ich auf # if-Feature-Flags zurückgreifen, um Funktionen auf Plattformen zu entfernen, die das Erstellen von Typen im laufenden Betrieb nicht unterstützen (in meiner Bibliothek in der Lage, einer Schnittstelle zuzuordnen, und ich erstelle einen Proxy im laufenden Betrieb).

@jbogard Wir verwenden ein boolesches Flag Env.SupportsEmit , um zur Laufzeit zu bestimmen, ob die Plattform Reflection unterstützt. Lassen Sie zu, wenn wir es verwenden, andernfalls greifen wir auf kompilierte Ausdrücke zurück. In diesem Sinne wäre es nützlich, wenn es ein Platform.SupportsEmit -Flag gäbe, mit dem jeder prüfen könnte, ob die laufende Plattform Reflection.Emit unterstützt.

Die #if -Anweisung würde das Erstellen mehrerer Plattform-Builds erfordern, was die Ursache für die grundlegende Änderung aller abhängigen Pakete und Projekte sein würde, die auf .netstandard2.0 abzielen, da sie auch .netstandard2.0 Abhängigkeiten erfordern.

Nur zur weiteren Diskussion möchte ich sicherstellen, dass wir alle auf der gleichen Seite sind, wenn es um den Unterschied zwischen System.Reflection.Emit und System.Reflection.Emit.Lightweight .

Dieses Problem sollte eigentlich in zwei separate Probleme aufgeteilt worden sein. 😄

  • Sollte es eine .Net Standard 2.0-Version von Reflection.Emit geben?
  • Sollte es eine .Net Standard 2.0-Version von System.Reflection.Emit.LightWeight geben?

System.Reflection.Emit

Dieses Paket enthält die AssemblyBuilder und zugehörigen Klassen, die wir zur Laufzeit benötigen, um Assemblys / Typen zu generieren.
Das Problem mit diesem Paket ist, dass es niemals als netstandard -Paket auf NuGet gestellt werden sollte, da das Generieren neuer Typen zur Laufzeit auf vollständigen AOT-Plattformen nicht unterstützt werden kann.
Ich vermute, dass Microsoft dies als netstandard -Paket hinzugefügt hat, um die Migration vom vollständigen Framework zu .Net Core- und netstandard -Bibliotheken zu vereinfachen. Im Nachhinein nicht wirklich die beste Idee.
Der "Köder und Schalter" -Ansatz (verstanden von 5 Menschen auf der ganzen Welt) ist ebenfalls keine großartige Lösung.

System.Reflection.Emit.LightWeight

Dieses Paket enthält die DynamicMethod, mit der Code dynamisch kompiliert werden kann, ohne dass neue Typen erstellt werden müssen. Die "dynamische Methode" ist im Grunde eine statische Methode, für die wir einen Delegaten erstellen können, der zum Aufrufen der Methode verwendet wird.
LambdaExpression.Compile ist im Grunde das gleiche und wenn wir uns die Implementierung im gesamten Framework ansehen, werden wir sehen, dass tatsächlich DynamicMethod unter der Decke verwendet wird.
Die Sache ist, dass LambdaExpression.Compile() auf allen Plattformen mit Interpretation auf AOT funktioniert. Aus diesem Grund gibt es keinen Grund, warum wir mit der zuvor in diesem Thread beschriebenen Technik kein System.Reflection.Emit.LightWeight -Paket erstellen können, das netstandard .

Ich vermute, dass der Grund für das Zurückverfolgen jetzt darin besteht, sicherzustellen, dass der Standard in Zukunft tatsächlich eine Bedeutung hat. Das Problem, wie ich es sehe, ist, dass wir möglicherweise Bibliothekspakete sehen, die auf netcoreapp anstatt auf netstandard abzielen, und das wäre wirklich schlecht, wenn es darum geht, das gesamte Konzept eines netstandard .

Mein Vorschlag ist, sich zu bemühen, System.Reflection.Emit.LightWeight als echtes netstandard -Paket zu veröffentlichen und weiterhin auf netcoreapp zu drängen, wenn es um System.Reflection.Emit .

@seesharper Soweit ich weiß, wird Reflection.Emit (einschließlich Reflection.Emit.Lightweight) hauptsächlich für die Leistung verwendet. Wenn Sie Reflection.Emit.Lightweight jedoch mit einem IL-Interpreter implementieren, ist die Leistung wahrscheinlich ziemlich schlecht. Daher bin ich nicht davon überzeugt, dass der Versuch, den IL-Interpretationsmodus in Reflection.Emit.Lightweight zu unterstützen, gerechtfertigt wäre.

Es ist auch seltsam, dass System.Reflection.Emit.ILGenerator weiterhin aufgeführt ist (https://www.nuget.org/packages/System.Reflection.Emit.ILGeneration), da es sich um ein netstandard1.6-Paket handelt, ILGenerator jedoch keine UWP-Implementierung hat (https://apisof.net/catalog/System.Reflection.Emit.ILGenerator).

Iow: ein bisschen chaotisch, nicht wahr?

@seesharper Guter Vorschlag.

@svick Ich denke nicht, dass das eine ausreichende Rechtfertigung ist, um es zu schneiden. Domänenspezifische Sprachen benötigen die Fähigkeit, zur Laufzeit Code zu erstellen. DSLs tauchen häufig genug in größeren Projekten auf ( Greenspuns zehnte Regel ), und es ist besser, wenn nicht jeder Autor seinen eigenen Interpreter dafür erfinden und schreiben muss (unter Verwendung regelmäßiger Reflexion und Invoke ). Wenn es sich um eine Standardkomponente handelt, werden zumindest die "informell spezifizierten und fehlerbehafteten" Teile der Regel verringert. Für die Leistung einer AOT-Targeting-Implementierung muss es sich nicht um einen IL-Interpreter handeln. Selbst auf Plattformen, auf denen ein Prozess keine ausführbaren Speicherseiten erstellen kann, können dynamische Methoden zu Thread-Code kompiliert werden, wie dies bei vielen FORTH-Implementierungen der Fall ist, und bei kleinen dynamischen Methoden, bei denen der "Methodenkörper" in einige Cache-Zeilen passt, die Der Laufzeitaufwand sollte recht gering sein.

Das Problem mit diesem Paket ist, dass es niemals als Netstandard-Paket auf NuGet gestellt werden sollte, da das Generieren neuer Typen zur Laufzeit auf vollständigen AOT-Plattformen nicht unterstützt werden kann.

Nicht zustimmen. Die wichtigsten .NET Core- und .NET Framework-Plattformen unterstützen dies, nur weil AOT-Umgebungen nicht ausschließen sollten, dass es die wichtigsten .NET-Plattformen unterstützt, die auf netstandard2.0 abzielen.

Ist dies nun die Strategie für .NET Standard für die Zukunft? APIs, die in AOT-Umgebungen nicht unterstützt werden, werden jetzt entfernt? Es wird also keine PlatformNotSupportedException Ausnahmen mehr geben, die APIs werden gerissen, anstatt sich wieder einer PCL-Teilmenge zuzuwenden? Oder werden wir inkonsistent sein und die API-Oberfläche für einige Funktionen selektiv reduzieren, andere jedoch weiterhin einbinden?

Die Unterstützung der Schnittmenge der APIs mit dem kleinsten gemeinsamen Nenner war das, was PCL tat, und führte zu einer schrecklichen Entwicklungserfahrung, die die PCL-Köder- und Switch-Technik erzwang und an mehrere plattformspezifische Implementierungen delegierte. Dies ist die Investition, die wir bei unserem Umzug weggeworfen haben. NET Standard.

Die beste Lösung war die vorhandene (zumal das Entfernen jetzt eine störende und bahnbrechende Änderung der transitiven Deps darstellt), mit der wir Reflection.Emit auf allen Plattformen verwenden können, die es unterstützen, während für diejenigen, die dies nicht tun, ein Fallback implementiert werden muss . Wenn Sie die Möglichkeit zur Verwendung von Reflection.Emit in .NET Standard entfernen, können Bibliotheken, die Reflection.Emit verwenden, nicht mehr auf .NET Standard abzielen. Was ist überhaupt der Sinn, wenn wir keine Funktionen verwenden können, die .NET Core und .NET Framework in einer plattformunabhängigen Abstraktion gemeinsam nutzen? Es würde nur unnötige Abstraktionen / Verwirrung / Komplexität zum .NET-Ökosystem ohne Vorteile hinzufügen.

Vielen Dank für das Feedback an alle. Aufgrund des überwältigenden Feedbacks haben wir die neueste Version der vorhandenen Pakete erneut aufgelistet:

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

Wie bereits in diesem Thread erwähnt, behaupten diese Pakete, netstandard1.1-kompatibel zu sein, aber das ist eine Lüge. Sie funktionieren nur mit .NET Core und .NET Framework. Wenn Sie sie also aus einer Netstandard-Bibliothek verwenden, ist zu erwarten, dass diese Bibliothek fehlschlägt, wenn sie auf einer anderen .NET Standard-Implementierung ausgeführt wird.

Wir haben immer noch keine großartige Lösung, um diese auf netstandard2.0 zu unterstützen, aber die Eigentümer ( @AtsushiKan @joshfree) von System.Relfection.Emit werden versuchen, die längerfristige Lösung herauszufinden.

@svick

Soweit ich weiß, wird Reflection.Emit (einschließlich Reflection.Emit.Lightweight) hauptsächlich für die Leistung verwendet. Wenn Sie Reflection.Emit.Lightweight jedoch mit einem IL-Interpreter implementieren, ist die Leistung wahrscheinlich ziemlich schlecht. Daher bin ich nicht davon überzeugt, dass der Versuch, den IL-Interpretationsmodus in Reflection.Emit.Lightweight zu unterstützen, gerechtfertigt wäre.

Ich verstehe, dass LambaExpression.Compile() und seine Ausführung auf AOT-Plattformen interpretiert werden und es daher nicht schlechter sein sollte, dies für System.Reflection.Emit.LightWeight tun.
Es gibt viele Bibliotheken, die dieses Paket verwenden, und ein "echtes" netstandard2.0-Paket würde es diesen Paketen plötzlich ermöglichen, auf Ihrem iPhone ausgeführt zu werden, ohne die Entwickler dieser Pakete zu zwingen, ihren Code neu zu schreiben, um ihn an die verschiedenen Plattformen anzupassen. Die Leistung würde sich verschlechtern, aber es würde genauso funktionieren wie heute mit LambdaExpression.Compile()

@mythz

Ist dies nun die Strategie für .NET Standard für die Zukunft? APIs, die in AOT-Umgebungen nicht unterstützt werden, werden jetzt entfernt? Es wird also keine PlatformNotSupportedException-Ausnahmen mehr geben. Die APIs werden gerissen, anstatt sich wieder einer PCL-Teilmenge zuzuwenden. Oder werden wir inkonsistent sein und die API-Oberfläche für einige Funktionen selektiv reduzieren, andere jedoch weiterhin einbinden?

IMHO ist das Werfen von PlatformNotSupportedException nur eine weitere Manifestation der API-Teilmenge, die wir bei PCLs gesehen haben. Wie bei System.Reflection.Emit.LightWeight können wir es tatsächlich implementieren und es gibt keinen Grund, ein PlatformNotSupportedException zu werfen. Ich stimme jedoch zu, dass es problematisch ist, dass weniger leistungsfähige Plattformen den Standard daran hindern, sich weiterzuentwickeln. Aber das ist eine Art Natur, einen Standard zu haben. Wenn Ergänzungen zum Standard vorgenommen werden, muss sichergestellt sein, dass es zumindest irgendwie möglich ist, von den Plattformen, die den Standard implementieren, implementiert zu werden. Zumindest unter den Hauptakteuren und würde sagen, Xamarin passt in diese Kategorie.

Diese Figur, wie sie heute steht, ist aus meiner Sicht eine Art Lüge. Xamarin behauptet, netstandard , aber diese Unterstützung ist mit Ausnahmen behaftet, die für uns vernünftig erscheinen könnten. Für den Anfänger ist es vielleicht nicht so einfach zu verstehen.

image

@ Weshaggard

Die weitere Veröffentlichung von System.Reflection.Emit als netstandard -Paket ist auf lange Sicht keine gute Lösung. Es macht den Standard wieder "false" und sollte nur für net / netcoreapp verfügbar sein. Es ist eine bittere Pille zum Schlucken, glauben Sie mir, ich weiß. Ich habe genau das gleiche Problem mit 'LightInject.Interception', das eine Proxy-Bibliothek ist, die System.Reflection.Emit . Aber ich würde lieber netcoreapp anstreben, als den Verbraucher anzulügen, dass diese Bibliothek überall laufen kann.

@seesharper

IMHO ist das Auslösen von PlatformNotSupportedException nur eine weitere Manifestation der API-Teilmenge, die wir bei PCLs gesehen haben. Wie bei System.Reflection.Emit.LightWeight können wir es tatsächlich implementieren, und es gibt keinen Grund, eine PlatformNotSupportedException auszulösen.

Sie sind überhaupt nicht gleichwertig. Der einzige Grund, warum .NET Standard nützlich ist, liegt in seiner erheblich größeren API-Oberfläche, mit der wir einen einzelnen Build erstellen können, der auf mehreren Plattformen ausgeführt werden kann. PCLs sind weitaus weniger nützlich, da die reduzierte API-Schnittmenge die Erstellung mehrerer plattformspezifischer Builds für nicht triviale Funktionen erzwingt. Ihre Funktionen sind nicht gleichwertig und die Lösungen, zu denen sie führen, unterscheiden sich sowohl für Bibliotheksautoren als auch für Konsumenten erheblich. Mit .NET Standard haben wir einen einzigen Build, der auf allen Plattformen ausgeführt wird, da wir zur Laufzeit prüfen können, ob die Plattform unterstützt Reflection.Emit, wenn dies nicht der Fall ist, greifen wir auf Lambda Expressions and Reflection zurück. Wenn diese APIs für .NET Standard-Bibliotheken nicht verfügbar wären, könnten wir keinen einzigen Build haben und müssten wieder nicht portable plattformspezifische Builds entwickeln und warten.

Die weitere Veröffentlichung von System.Reflection.Emit als Netstandard-Paket ist auf lange Sicht keine gute Lösung. Es macht den Standard wieder "false" und sollte nur für net / netcoreapp verfügbar sein.

Das Erzwingen der Erstellung und Abhängigkeit von plattformspezifischen Builds ist ein weitaus schlechteres Ergebnis, insbesondere. mit so vielen transitiven Abhängigkeiten, die bereits davon abhängen. Der Hauptvorteil von .NET Standard besteht darin, dass Bibliotheken und Projekte für eine einzelne nützliche Abstraktion erstellt werden können. Wenn wir damit nicht auf die in .NET Core und .NET Framework verfügbaren Hauptfunktionen zugreifen können, kann die primäre Verwendung nicht aufgelöst werden -case und kann auch nicht existieren, da es dem .NET-Ökosystem nur mehr Abstraktionen / Verwirrung hinzufügt, ohne Vorteile gegenüber PCLs zu haben.

PCLs haben bereits versucht, sich an Abstraktionen zu binden, die nur den Schnittpunkt der auf jeder Plattform verfügbaren API-Funktionen offenlegen. Dies ist genau das, worauf Sie zurückgreifen möchten, da Sie nur Zugriff auf APIs haben, die auf jeder Plattform verfügbar sind und im weiteren Sinne nur APIs enthalten verfügbar in der am meisten eingeschränkten Plattform.

Eine breitere API-Oberfläche in .NET Standard ist weitaus nützlicher und gibt Bibliotheksautoren die Freiheit, frei wählen zu können, wie sie mit der Unterstützung für verschiedene Plattformen umgehen möchten. Wenn diese APIs nicht verfügbar wären, würde diese Option nicht existieren Erzwingen Sie plattformspezifische Builds und erzwingen Sie, dass alle abhängigen Bibliotheken und Projekte auch plattformspezifische Builds verwalten. Dies führt zu Reibung, Fragmentierung, verringert die Portabilität und beschränkt die Unterstützung nur auf die Plattformen, für die Autoren Builds für alle Plattformen verwalten, die .NET Standard unterstützen diese Funktion.

Es ist nicht nur eine Frage der Präferenz, das Entfernen der Mainstream-API-Unterstützung hat weitreichende störende Auswirkungen auf die verfügbaren Lösungen, erzwingt unnötige plattformspezifische Builds, die sich auf den Nutzen von Bibliotheken auswirken, während jede .NET Standard-Bibliothek und jedes Projekt, das sie verwendet, beschädigt wird.

@ Weshaggard

Wir haben immer noch keine großartige Lösung, um diese auf netstandard2.0 zu unterstützen, aber die Eigentümer ( @AtsushiKan @joshfree) von System.Relfection.Emit werden versuchen, die längerfristige Lösung herauszufinden.

Wie wäre es, wenn Sie den iDiots und Kontrollfreaks, die jedem, der ihre Plattformen verwendet, AOT-only aufzwingen, mitteilen, dass sie ihre schlechten Plattformregeln formulieren und korrigieren müssen? (Um ehrlich zu sein, wissen wir alle, worum es hier wirklich geht: um einige sehr spezifische schlechte Schauspieler in der mobilen Welt.)

@mythz du hast absolut recht.

@masonwheeler

Ich verstehe vollkommen, dass das Verstecken des Ref-Emit-Pakets angesichts des dadurch verursachten Ausfalls frustrierend ist. Ich verstehe auch, dass die Optimierung für Ausführungsumgebungen, die Sie nicht interessieren, ärgerlich sein kann, insbesondere wenn dies Kompromisse beinhaltet, die sich auf Szenarien auswirken, die Sie negativ interessieren.

Davon abgesehen habe ich Ihren Kommentar als "missbräuchlich" markiert, da er nicht konstruktiv ist. Beleidigende Menschen werden diese Probleme nicht lösen. Bedenken Sie auch, dass dies keine Richtlinie ist, die wir kontrollieren. Die Tatsache, dass Sie unter iOS zur Laufzeit keinen Code generieren und ausführen können, ist eine Richtlinienentscheidung von Apple. In einigen Fällen handelt es sich auch nicht um eine politische, sondern um eine technologische Einschränkung.

Es gibt drei Möglichkeiten mit Reflexion zu emittieren:

  1. Korrigieren Sie die aktuellen Pakete und lassen Sie sie auf .NET Standard 2.0 arbeiten . Das Problem ist eine seltsame Vererbungsbeziehung zwischen Type und TypeInfo in .NET Standard 1.x im Vergleich zu 2.0 und nicht öffentlichen Konstruktoren. Ich kann näher darauf eingehen, aber es ist etwas schwierig, das Paket ohne Wiederherstellung von Hacks tatsächlich baubar zu machen, weshalb wir uns ursprünglich entschieden haben, die Pakete auszublenden.

  2. Hinzufügen von Reflection Emit zu .NET Standard vNext . Um nur AOT-Szenarien zu unterstützen, würde dies wahrscheinlich eine Funktions-API beinhalten, mit der Verbraucher prüfen können, ob die Codegenerierung unterstützt oder effizient ist (dh ob wir eine echte Ausführung anstelle einer Interpretation verwenden).

  3. Keine Reflection-Emission für .NET Standard verfügbar machen und Bibliotheksautoren müssen mehrere Ziele festlegen . Dies war im Grunde der ursprüngliche Pfad, als wir anfingen, das Paket zu verstecken.

Im Moment neigen wir zur ersten Option, aber die zweite Option steht ebenfalls auf dem Tisch.

Ich bin für 2. Es ist allgegenwärtig genug, dass es da sein sollte. Wir brauchen die Fähigkeitsprüfung sowieso aus anderen Gründen.

Ich bin für 2. Es ist allgegenwärtig genug, dass es da sein sollte. Wir brauchen die Fähigkeitsprüfung sowieso aus anderen Gründen.

Ich auch, aber es wird niemandem helfen, der sich derzeit auf .NET Standard 2.0 verlässt, da dies eine neue Version des Standards erfordert. Die fraglichen APIs sind jedoch bereits vorhanden.

Daher denke ich über eine minimale Korrektur nach, damit diese Pakete unverändert funktionieren, aber auch über .NET Standard 2.0 vNext.

@terrajobst Gibt es etwas an Option 1, das Option 2 schwieriger macht? Es scheint mir, dass es ein gutes kurzfristiges Ziel wäre, eine Version der Pakete zu erhalten, die auf netstandard2.0 abzielen, anstatt das Paketdiagramm netstandard1.1 einholen zu müssen. Dann könnte es für vNext des Standards Teil davon werden, und Sie würden die Pakete nicht mehr benötigen.

Wenn es keinen guten Grund gibt, dies nicht zu tun, stimme ich für 1 und 2.

@bording

Sieht so aus, als hätten wir praktisch zur gleichen Zeit gepostet. Hoffentlich geht mein Kommentar auf Ihre Frage ein :-)

Bitte beachten Sie, dass netstandard2.0 die statische Methode System.Reflection.Assembly.Load(byte[] rawAssembly) , mit der eine Assembly aus einem Binärbild-Byte-Array geladen wird. Dies bedeutet, dass es möglich ist, nicht alle, aber die meisten System.Reflection.Emit APIs-Kompatiblen unter reinen netstandard2.0 zu implementieren.

(Entschuldigung, ich weiß nicht, wie viele Plattformen Assembly.Load ohne PNSE unterstützen)

@GlassGrass Für welche Frameworks würde sich eine Implementierung von netstandard2.0 vorstellen?

Ich kann mir sicherlich eine Implementierung

Frameworks mit einer JIT (und Assembly.Load) können Ref.Emit auch direkt unterstützen und ihre Ref.Emit-Implementierung anstelle einer netstandard2.0-Version bereitstellen. Ich weiß, dass dies zumindest bei desktop / .netcore / .netnative der Fall ist. Die ersten beiden unterstützen ref.emit und stellen eine Implementierung bereit, die spätere unterstützt weder eine JIT noch das dynamische Laden von Assemblys.

Ich denke, es wäre ein interessantes Projekt für jemanden, in corefxlab herumzuspielen, um etwas über System.Reflection.Metadata zu schreiben, das wie Ref.Emit (oder besser) aussieht. Ich bin mir nicht sicher, ob sich das schon jemand ansieht. / cc @nguerrera @tmat

Ich denke, es wäre ein interessantes Projekt für jemanden, in corefxlab herumzuspielen, um etwas über System.Reflection.Metadata zu schreiben, das wie Ref.Emit (oder besser) aussieht.

Das steht auf meinem Teller: (https://github.com/dotnet/corefx/issues/4491 und https://github.com/dotnet/corefx/issues/2800)

https://github.com/dotnet/corefx/issues/2800 wird an erster Stelle stehen, da das Ref-Emit-Material wahrscheinlich eine Erweiterung davon ist. Ich habe diese Woche mit dem Prototyping von 2800 begonnen und werde diese Arbeit in den kommenden Monaten fortsetzen. Ich verschiebe es nicht nach corefxlab, bis ich viel weiter bin. Der Workflow ist dort für meinen Geschmack zu ineffizient.

@AtsushiKan :

Ich habe an anderer Stelle bereits Folgendes erwähnt: Eine Sache, die System.Reflection.Metadata und Assembly.Load(byte[]) nicht können, ist die inkrementelle typweise Ausgabe. Sie können nicht einen Typ ausgeben, sondern einen anderen ... Sie können immer nur vollständige Assemblys ausgeben, was bedeutet, dass dies nicht allzu nützlich ist, um beispielsweise Bibliotheken zu verspotten, die auf der dynamischen Generierung von Proxy-Typen beruhen.

Natürlich kann man immer nur Assemblys vom Typ Single erstellen, aber dies wird möglicherweise ineffizient und schwierig, wenn Interna für die dynamisch generierten Assemblys über [assembly: InternalsVisibleTo] sichtbar gemacht werden (eine andere Sache, die das Verspotten / Testen von Bibliotheken häufig erfordert). Sie müssen in der Lage sein, mehreren dynamischen Baugruppen mit einem Typ dieselbe Identität / denselben Namen zu geben, damit dies funktioniert. (Die Laufzeit erlaubt dies möglicherweise bereits in der Praxis, aber ich kann keine Dokumentation finden, die dies offiziell bestätigt.)

@stakx Sie können System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute an die dynamische Assembly senden, damit diese auf nicht öffentliche Mitglieder der angegebenen Assembly zugreifen kann, anstatt IVT zu verwenden.

@tmat : Das ist interessant. Ist dieses Attribut irgendwo offiziell dokumentiert?

Es ist schade, dass dieses spezielle Attribut nicht offiziell dokumentiert ist. Es macht es zu einem Glücksspiel, es außerhalb der Laufzeit zu verwenden.

Würde dies zu .NET core 3.0 hinzugefügt?

cc @steveharter @joshfree

@karelz https://github.com/dotnet/corefx/issues/30654 verfolgt die Arbeit für 3.0

@joshfree ist dies ein Betrüger, oder deckt es mehr ab?

@karelz Es wurde das Problem behoben, dass das Ref.Emit-Paket fälschlicherweise aus Nuget entfernt wurde und das Paket dann von @weshaggard erneut aufgelistet wurde. Ich denke, dieses Problem kann jetzt geschlossen werden, da die verbleibende Arbeit mit dotnet / corefx # 30654 verfolgt wird.

OK, dann schließen :) ... die verbleibende Arbeit wird wie oben erwähnt in dotnet / corefx # 30654 verfolgt.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

matty-hall picture matty-hall  ·  3Kommentare

iCodeWebApps picture iCodeWebApps  ·  3Kommentare

bencz picture bencz  ·  3Kommentare

v0l picture v0l  ·  3Kommentare

sahithreddyk picture sahithreddyk  ·  3Kommentare