Kann ich in C # eine Variable vom Typ Objekt in eine Variable vom Typ T umwandeln, wobei T in einer Typvariablen definiert ist?
c#
reflection
types
Theringostarrs
quelle
quelle
Type
Variable haben, können Sie mithilfe der Reflektion eine Instanz dieses Typs erstellen. Anschließend können Sie eine generische Methode verwenden, um den gewünschten Typ zurückzugeben, indem Sie ihn aus einem Parameter dieses Typs ableiten. Leider hat jede Reflektionsmethode, die eine Instanz eines Typs erstellt, einen Rückgabetyp vonobject
, sodass auch Ihre generischeCastByExample
Methode verwendet wirdobject
. Es gibt also wirklich keine Möglichkeit, dies zu tun, und selbst wenn dies der Fall wäre, was würden Sie mit dem neu gegossenen Objekt tun? Sie konnten seine Methoden oder irgendetwas nicht verwenden, weil Sie seinen Typ nicht kennen.object
oder verwendendynamic
. Wenn Sie externe Module dynamisch laden möchten, können Sie die Klassen eine gemeinsame Schnittstelle verwenden lassen und das Objekt in diese umwandeln. Wenn Sie den Code von Drittanbietern nicht steuern, erstellen Sie kleine Wrapper und implementieren Sie die Schnittstelle darauf.Antworten:
Hier ist ein Beispiel für eine Besetzung und einen Konvertiten:
Bearbeiten:
Einige Leute in den Kommentaren sagen, dass diese Antwort die Frage nicht beantwortet. Aber die Linie
(T) Convert.ChangeType(input, typeof(T))
bietet die Lösung. DieConvert.ChangeType
Methode versucht, ein beliebiges Objekt in den als zweites Argument angegebenen Typ zu konvertieren.Beispielsweise:
Ich habe die Antwort mit Generika geschrieben, weil ich denke , es ist ein sehr wahrscheinlich zu unterzeichnen ist der Codegeruch , wenn Sie Guss wollen
a something
zu ,a something else
ohne dass eine tatsächliche Art der Handhabung. Mit geeigneten Schnittstellen sollte dies in 99,9% der Fälle nicht erforderlich sein. Es gibt vielleicht ein paar Randfälle, wenn es um Überlegungen geht, die sinnvoll sein könnten, aber ich würde empfehlen, diese Fälle zu vermeiden.Bearbeiten 2:
Einige zusätzliche Tipps:
object
oderdynamic
Variablen.quelle
T
als solche.Convert.ChangeType(input, typeof(T));
gibt die Zeile die Lösung. Sie können leicht durchtypeof(T)
eine vorhandene Typvariable ersetzen . Eine bessere Lösung (wenn möglich) wäre, den dynamischen Typ insgesamt zu verhindern.T
die keine verfügbar ist.T
aber Sie erhalten trotzdem nur einobject
als Referenz. hmm, ich fand die Frage interessant in der Prämisse, dass OP nur dieType
Variable und keine anderen Informationen hat. Als ob die Methodensignatur wäreConvert(object source, Type destination)
:) Trotzdem bekomme ich ur pointAndere Antworten erwähnen nicht den "dynamischen" Typ. Um eine weitere Antwort hinzuzufügen, können Sie das resultierende Objekt mit dem Typ "dynamisch" speichern, ohne das konvertierte Objekt mit einem statischen Typ umwandeln zu müssen.
Beachten Sie, dass der Compiler bei Verwendung von "dynamic" die statische Typprüfung umgeht, die zu möglichen Laufzeitfehlern führen kann, wenn Sie nicht vorsichtig sind.
quelle
Hier ist meine Methode, um ein Objekt umzuwandeln, aber nicht in eine generische Typvariable, sondern in eine
System.Type
dynamische:Ich erstelle zur Laufzeit einen Lambda-Ausdruck mit dem
System.Linq.Expressions
TypFunc<object, object>
, der seine Eingabe entpackt, die gewünschte Typkonvertierung durchführt und dann das Ergebnis in einem Feld ausgibt. Ein neuer wird nicht nur für alle Typen benötigt, in die umgewandelt wird, sondern auch für die Typen, die umgewandelt werden (aufgrund des Unboxing-Schritts). Das Erstellen dieser Ausdrücke ist aufgrund der Reflexion, der Kompilierung und der dynamischen Methodenerstellung, die unter der Haube durchgeführt wird, sehr zeitaufwändig. Glücklicherweise können die Ausdrücke nach dem Erstellen wiederholt und ohne hohen Overhead aufgerufen werden, sodass ich jeden einzelnen zwischenspeichere.Beachten Sie, dass dies keine Magie ist. Das Casting erfolgt nicht wie beim Schlüsselwort im Code, sondern
dynamic
nur die zugrunde liegenden Daten des Objekts. Bei der Kompilierung müssen wir immer noch genau herausfinden, um welchen Typ es sich bei unserem Objekt handelt, was diese Lösung unpraktisch macht. Ich habe dies als Hack geschrieben, um Konvertierungsoperatoren aufzurufen, die durch beliebige Typen definiert sind, aber vielleicht kann jemand da draußen einen besseren Anwendungsfall finden.quelle
using System.Linq.Expressions;
Type t = typeof(MyGeneric<>).MakeGenericType(obj.OutputType); var a = (t)Convert.ChangeType(obj, t); var b = (t)Caster.Cast(t, obj);
Type
. Sie können nicht mit normaler Casting-Syntax umwandeln, wenn Sie nur das Type-Objekt haben. Wenn Sie das Objekt zur Kompilierungszeit als Typ T und nicht zur Laufzeit verwenden möchten, müssen Sie es mit einer Typvariablen oder nur mit dem tatsächlichen Typnamen umwandeln. Ersteres können Sie mit der Antwort von Zaphrax tun.Wenn Sie das Ein- und Auspacken der Einfachheit halber beiseite lassen, ist beim Casting entlang der Vererbungshierarchie keine bestimmte Laufzeitaktion erforderlich. Es ist meistens eine Sache zur Kompilierungszeit. Im Wesentlichen weist eine Umwandlung den Compiler an, den Wert der Variablen als einen anderen Typ zu behandeln.
Was könntest du nach der Besetzung tun? Sie kennen den Typ nicht und können daher keine Methoden dafür aufrufen. Es würde nichts Besonderes geben, was du tun könntest. Insbesondere kann es nur nützlich sein, wenn Sie die möglichen Typen zur Kompilierungszeit kennen, sie manuell umwandeln und jeden Fall separat mit
if
Anweisungen behandeln:quelle
Wie konntest du das tun? Sie benötigen eine Variable oder ein Feld vom Typ T, in dem Sie das Objekt nach der Umwandlung speichern können. Wie können Sie jedoch eine solche Variable oder ein solches Feld haben, wenn Sie T nur zur Laufzeit kennen? Also, nein, das ist nicht möglich.
quelle
CastTo
MethodeObject
?Wenn es um das Casting nach Enum-Typ geht:
Und du wirst es so nennen:
Dies war für mich wichtig, wenn ich den Beschreibungsattributwert mehrerer Aufzählungstypen durch den int-Wert erhalten wollte:
und dann:
Alternativ (besserer Ansatz) könnte ein solches Casting so aussehen:
quelle
Nachdem ich bei der Verwendung der Antwort von Zyphrax (mit Ausnahme der Implementierung der Schnittstelle) keine Ausnahme gefunden hatte, um das Problem zu umgehen, versuchte ich etwas Unkonventionelles und arbeitete für meine Situation.
Verwenden des Newtonsoft.Json-Nuget-Pakets ...
quelle
Schaden, das Problem ist, dass Sie kein T haben.
Sie haben nur eine Typvariable.
Tipp an MS, wenn Sie so etwas tun könnten
TryCast<typeof(MyClass)>
wenn würde alle unsere Probleme lösen.
quelle
Ich werde nie verstehen, warum Sie bis zu 50 Ruf benötigen, um einen Kommentar zu hinterlassen, aber ich musste nur sagen, dass die Antwort von @Curt genau das ist, wonach ich gesucht habe und hoffentlich jemand anderes.
In meinem Beispiel habe ich ein ActionFilterAttribute, mit dem ich die Werte eines JSON-Patchdokuments aktualisiert habe. Ich wusste nicht, was das T-Modell für das Patch-Dokument war, um es zu einem einfachen JsonPatchDocument zu serialisieren und zu deserialisieren, es zu ändern, und dann, weil ich den Typ hatte, es wieder zu dem Typ zu serialisieren und zu deserialisieren.
quelle
quelle
noch sauberer:
quelle
Wenn Sie Objekte zur Laufzeit umwandeln müssen, ohne den Zieltyp zu kennen, können Sie mithilfe der Reflektion einen dynamischen Konverter erstellen.
Dies ist eine vereinfachte Version (ohne generierte Caching-Methode):
dann kannst du es nennen:
quelle