Festlegen einer Eigenschaft durch Reflexion mit einem String-Wert
-
23-08-2019 - |
Frage
Ich möchte eine Eigenschaft eines Objekts durch Reflexion setzen, mit einem Wert vom Typ string
.
So zum Beispiel, nehme ich eine Ship
Klasse, mit einer Eigenschaft von Latitude
, die ein double
ist.
Hier ist, was ich tun möchte:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);
Wie dies wirft einen ArgumentException
:
Objekt vom Typ 'System.String' nicht auf den Typ umgewandelt werden 'System.Double'.
Wie kann ich Wert auf den richtigen Typ umwandeln, basierend auf propertyInfo
?
Lösung
Sie können mit Convert.ChangeType()
- Es ermöglicht Ihnen, Laufzeitinformationen zu verwenden, auf jedem Typ IConvertible
Darstellungsformate zu ändern. Nicht alle Konvertierungen sind jedoch möglich, und Sie können Sonderfall Logik schreiben müssen, wenn Sie Konvertierungen von Typen unterstützen möchten, die nicht IConvertible
.
Der entsprechende Code (ohne Ausnahmebehandlung oder Sonderfall Logik) wäre:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Andere Tipps
Wie mehrere andere gesagt haben, Sie wollen Convert.ChangeType
verwenden:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
In der Tat, empfehle ich Ihnen Blick auf die gesamte Convert
Klasse .
Diese Klasse und viele andere nützliche Klassen sind Teil der System
Namespace . Ich finde es nützlich, dass die Namespace jedes Jahr oder so zu scannen, um zu sehen, welche Funktionen ich verpasst habe. Probieren Sie es aus!
Ich bemerke eine Menge Leute Convert.ChangeType
empfehlen - Dies funktioniert für einige Fälle jedoch, sobald Sie nullable
Arten starten denen Sie beginnen InvalidCastExceptions
Empfang:
Es wurde ein Wrapper ein paar Jahre geschrieben vor, dies zu umgehen, aber das ist auch nicht perfekt.
Sie können einen Typkonverter (keine Fehlerprüfung) verwenden:
Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
In Bezug auf den Code der Organisation, könnten Sie ein erstellen Art-of mixin , die in Code wie folgt ergeben würde:
Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");
Das mit diesem Code erreicht werden würde:
public interface MPropertyAsStringSettable { }
public static class PropertyAsStringSettable {
public static void SetPropertyAsString(
this MPropertyAsStringSettable self, string propertyName, string value) {
var property = TypeDescriptor.GetProperties(self)[propertyName];
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
}
}
public class Ship : MPropertyAsStringSettable {
public double Latitude { get; set; }
// ...
}
MPropertyAsStringSettable
kann für viele verschiedene Klassen wiederverwendet werden.
Sie können auch eigene erstellen Typ Konverter befestigen auf Ihre Eigenschaften oder Klassen:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Ich habe versucht, die Antwort von LBushkin und es funktionierte großartig, aber es wird nicht funktionieren für Nullwerte und Nullable-Felder. Also habe ich es so weit geändert:
propertyName= "Latitude";
PropertyInfo propertyInfo = ship.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
Type t = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
propertyInfo.SetValue(ship, safeValue, null);
}
Sie suchen wahrscheinlich für die Convert.ChangeType
Methode. Zum Beispiel:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Mit Convert.ChangeType
und immer den Typ aus der PropertyInfo.PropertyType
zu konvertieren.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
Ich beantworte diese mit einer allgemeinen Antwort. Normalerweise werden diese Antworten arbeiten nicht mit guids. Hier ist eine Arbeitsversion mit guids zu.
var stringVal="6e3ba183-89d9-e611-80c2-00155dcfb231"; // guid value as string to set
var prop = obj.GetType().GetProperty("FooGuidProperty"); // property to be setted
var propType = prop.PropertyType;
// var will be type of guid here
var valWithRealType = TypeDescriptor.GetConverter(propType).ConvertFrom(stringVal);
Oder Sie könnten versuchen:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Wenn Sie Metro App schreiben, sollten Sie einen anderen Code verwenden:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));
Hinweis:
ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
statt
ship.GetType().GetProperty("Latitude");
den folgenden Code verwenden, sollten Sie Ihr Problem lösen:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
Suchen Sie mit Reflexion zu spielen, um oder suchen Sie ein Produktions Stück Software zu bauen? Ich würde fragen, warum Sie Reflektion verwenden eine Eigenschaft zu setzen.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;