2009-07-06 11 views
251

Ich möchte eine Eigenschaft eines Objekts durch Reflection mit einem Wert vom Typ string festlegen. Nehmen wir zum Beispiel an, ich habe eine Klasse Ship mit einer Eigenschaft Latitude, die eine double ist.Festlegen einer Eigenschaft durch Reflexion mit einem Zeichenfolgenwert

Hier ist, was Ich mag würde tun:

Ship ship = new Ship(); 
string value = "5.5"; 
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude"); 
propertyInfo.SetValue(ship, value, null); 

Wie ist, das eine ArgumentException wirft:

Objekt vom Typ 'System.String' nicht auf den Typ ‚System umgewandelt werden. Doppelt'.

Wie kann ich den Wert in den richtigen Typ konvertieren, basierend auf propertyInfo?

+1

Frage für Sie: ist dieser Teil einer benutzerdefinierten ORM-Lösung? – user3308043

Antwort

419

Sie können Convert.ChangeType() verwenden - Sie können Laufzeitinformationen für einen beliebigen IConvertible-Typ verwenden, um Repräsentationsformate zu ändern. Es sind jedoch nicht alle Konvertierungen möglich, und Sie müssen möglicherweise spezielle Falllogik schreiben, wenn Sie Konvertierungen von Typen unterstützen möchten, die nicht IConvertible sind.

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); 
31

Wie einige andere haben gesagt, Sie wollen Convert.ChangeType verwenden:

propertyInfo.SetValue(ship, 
    Convert.ChangeType(value, propertyInfo.PropertyType), 
    null); 

In der Tat, empfehle ich Ihnen die gesamte Convert Class betrachten.

Diese Klasse und viele andere nützliche Klassen sind Teil der System Namespace. Ich finde es nützlich, diesen Namespace jedes Jahr zu scannen, um zu sehen, welche Features ich verpasst habe. Versuche es!

+1

Das OP möchte wahrscheinlich die allgemeine Antwort, um eine Eigenschaft eines beliebigen Typs zu setzen, der eine offensichtliche Umwandlung von einer Zeichenkette hat. –

+0

Guter Punkt. Ich bearbeite und zeige auf die echten Beantworter, oder lösche meine, wenn jemand hinzufügen wird, was ich über den Rest des Namensraums gesagt habe. –

3

Oder Sie könnten versuchen:

propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null); 

//But this will cause problems if your string value IsNullOrEmplty... 
6

Sie sind wahrscheinlich für die Convert.ChangeType Methode suchen. 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); 
5

Mit Convert.ChangeType und immer den Typ aus den PropertyInfo.PropertyType zu konvertieren.

-6

Möchten Sie mit Reflection spielen oder möchten Sie eine Produktionseinheit von Software erstellen? Ich würde fragen, warum Sie Reflektion verwenden, um eine Eigenschaft festzulegen.

Double new_latitude; 

Double.TryParse (value, out new_latitude); 
ship.Latitude = new_latitude; 
+0

Sie sollten respektieren, was die Leute versuchen zu tun und nicht, was Sie denken, dass sie tun müssen. Downvoted. (Von 'GenericProgramming.exe: ReflectionBenefits()') –

18

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 empfangen wird:

http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

Ein Wrapper wurde vor ein paar Jahren geschrieben, um damit umzugehen, aber das ist auch nicht perfekt.

http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

11

können Sie einen Typkonverter verwenden (keine Fehlerprüfung):

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 zu organisieren, können Sie eine kind-of mixin erstellen, die im Code führen würde, wie dies:

Ship ship = new Ship(); 
ship.SetPropertyAsString("Latitude", "5.5"); 

Dies wäre ach ieved mit diesem Code:

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 type converters zu Ihren Eigenschaften oder Klassen befestigen:

public class Ship : MPropertyAsStringSettable { 
    public Latitude Latitude { get; set; } 
    // ... 
} 

[TypeConverter(typeof(LatitudeConverter))] 
public class Latitude { ... } 
+0

Gibt es einen bestimmten Grund, warum Sie das Marker-Interface hinzugefügt haben, anstatt nur 'object' zu verwenden? – Groo

+0

Ja, die Marker-Schnittstelle dient als Platzhalter, zu dem die Erweiterungsmethoden hinzugefügt werden können. Die Verwendung von "object" würde die Erweiterungsmethoden allen Klassen hinzufügen, was im Allgemeinen nicht wünschenswert ist. –

2

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"); 

anstelle von

3

Ich versuchte die Antwort von LBushkin und es funktionierte großartig, aber es funktioniert nicht für Null-Werte und Nullable-Felder. Also habe ich es zu diesem 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); 
}