392 Stimmen

Casting einer Variablen mit einer Typvariablen

Kann ich in C# eine Variable vom Typ object auf eine Variable des Typs T donde T ist definiert in einem Type variabel?

266voto

Zyphrax Punkte 17659

Hier ist ein Beispiel für eine Besetzung und eine Umwandlung:

using System;

public T CastObject<T>(object input) {   
    return (T) input;   
}

public T ConvertObject<T>(object input) {
    return (T) Convert.ChangeType(input, typeof(T));
}

Bearbeiten:

In den Kommentaren sagen einige, dass diese Antwort die Frage nicht beantwortet. Aber die Zeile (T) Convert.ChangeType(input, typeof(T)) bietet die Lösung. Die Convert.ChangeType Methode versucht, ein beliebiges Objekt in den als zweites Argument angegebenen Typ zu konvertieren.

Zum Beispiel:

Type intType = typeof(Int32);
object value1 = 1000.1;

// Variable value2 is now an int with a value of 1000, the compiler 
// knows the exact type, it is safe to use and you will have autocomplete
int value2 = Convert.ChangeType(value1, intType);

// Variable value3 is now an int with a value of 1000, the compiler
// doesn't know the exact type so it will allow you to call any
// property or method on it, but will crash if it doesn't exist
dynamic value3 = Convert.ChangeType(value1, intType);

Ich habe die Antwort mit Generika geschrieben, weil ich denke, dass es ein sehr wahrscheinliches Zeichen von Codegeruch ist, wenn man die a something a a something else ohne einen tatsächlichen Typ zu behandeln. Mit geeigneten Schnittstellen sollte das in 99,9% der Fälle nicht notwendig sein. Es gibt vielleicht ein paar Randfälle, wenn es um Reflexion geht, dass es sinnvoll sein könnte, aber ich würde empfehlen, diese Fälle zu vermeiden.

Bearbeiten 2:

Ein paar zusätzliche Tipps:

  • Versuchen Sie, Ihren Code so typsicher wie möglich zu halten. Wenn der Compiler den Typ nicht kennt, kann er nicht prüfen, ob Ihr Code korrekt ist, und Dinge wie die automatische Vervollständigung werden nicht funktionieren. Einfach gesagt: wenn man den Typ/die Typen zur Kompilierzeit nicht vorhersagen kann, wie soll der Compiler dann in der Lage sein ?
  • Wenn die Klassen, mit denen Sie arbeiten eine gemeinsame Schnittstelle implementieren können Sie den Wert auf diese Schnittstelle übertragen. Andernfalls sollten Sie Ihre eigene Schnittstelle erstellen und die Klassen diese Schnittstelle implementieren lassen.
  • Wenn Sie mit externen Bibliotheken arbeiten, die Sie dynamisch importieren, sollten Sie auch nach einer gemeinsamen Schnittstelle suchen. Andernfalls sollten Sie kleine Wrapper-Klassen erstellen, die die Schnittstelle implementieren.
  • Wenn Sie Aufrufe auf das Objekt machen wollen, aber sich nicht um den Typ kümmern, dann speichern Sie den Wert in einem object o dynamic variabel.
  • Generika kann eine großartige Möglichkeit sein, wiederverwendbaren Code zu erstellen, der für viele verschiedene Typen gilt, ohne dass man die genauen Typen kennen muss.
  • Wenn Sie nicht weiterkommen, sollten Sie einen anderen Ansatz wählen oder den Code überarbeiten. Muss Ihr Code wirklich so dynamisch sein? Muss er jeden Typ berücksichtigen, den es gibt?

162voto

maulik13 Punkte 3466

Andere Antworten erwähnen den "dynamischen" Typ nicht. Um eine weitere Antwort hinzuzufügen: Sie können den "dynamischen" Typ verwenden, um das resultierende Objekt zu speichern, ohne das konvertierte Objekt in einen statischen Typ umwandeln zu müssen.

dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();

Denken Sie daran, dass der Compiler mit der Verwendung von "dynamisch" die statische Typüberprüfung umgeht, was bei Unachtsamkeit zu Laufzeitfehlern führen kann.

Außerdem wird angenommen, dass obj eine Instanz von Type typeVar ist oder in diesen Typ konvertierbar ist.

8voto

mmx Punkte 400975

Der Einfachheit halber lassen wir Boxing und Unboxing beiseite, denn das Casting entlang der Vererbungshierarchie ist keine spezifische Laufzeitaktion. Es ist hauptsächlich eine Sache der Kompilierzeit. Im Wesentlichen weist ein Cast den Compiler an, den Wert der Variablen als einen anderen Typ zu behandeln.

Was kann man nach dem Gipsverband tun? Da Sie den Typ nicht kennen, können Sie auch keine Methoden darauf aufrufen. Es gäbe keine speziellen Dinge, die Sie tun könnten. Insbesondere kann es nur dann nützlich sein, wenn man die möglichen Typen zur Kompilierungszeit kennt, sie manuell castet und jeden Fall separat behandelt mit if Erklärungen:

if (type == typeof(int)) {
    int x = (int)obj;
    DoSomethingWithInt(x);
} else if (type == typeof(string)) {
    string s = (string)obj;
    DoSomethingWithString(s);
} // ...

7voto

Curt Punkte 131

Nachdem ich nichts gefunden habe, um die Ausnahme "Object must implement IConvertible" zu umgehen, wenn ich die Antwort von Zyphrax verwende (außer der Implementierung der Schnittstelle). Ich versuchte etwas ein wenig unkonventionell und arbeitete für meine Situation.

Verwendung des Nuget-Pakets Newtonsoft.Json...

var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);

4voto

Daniel Brückner Punkte 57561

Wie konnten Sie das tun? Sie brauchen eine Variable oder ein Feld vom Typ T, in dem Sie das Objekt nach dem Cast speichern können, aber wie können Sie eine solche Variable oder ein solches Feld haben, wenn Sie T nur zur Laufzeit kennen? Also, nein, es ist nicht möglich.

Type type = GetSomeType();
Object @object = GetSomeObject();

??? xyz = @object.CastTo(type); // How would you declare the variable?

xyz.??? // What methods, properties, or fields are valid here?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X