L'impostazione di una proprietà da parte di riflessione con un valore di stringa
-
23-08-2019 - |
Domanda
Mi piacerebbe impostare una proprietà di un oggetto attraverso la riflessione, con un valore di tipo string
.
Così, per esempio, supponiamo di avere una classe Ship
, con una proprietà di Latitude
, che è un double
.
Ecco cosa mi piacerebbe fare:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);
Come è, questo getta un ArgumentException
:
Oggetto di tipo 'System.String' non può essere convertito nel tipo 'System.Double'.
Come posso convertire il valore per il tipo corretto, sulla base di propertyInfo
?
Soluzione
È possibile utilizzare Convert.ChangeType()
- Esso consente di utilizzare informazioni di runtime su qualsiasi tipo IConvertible
cambiare formati di rappresentazione. Non tutte le conversioni sono possibili, però, e potrebbe essere necessario scrivere la logica speciale caso, se si desidera supportare conversioni da tipi che non sono IConvertible
.
Il corrispondente codice (senza manipolazione eccezione o logica speciale caso) sarebbe:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Altri suggerimenti
Come molti altri hanno detto, che si desidera utilizzare Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
In realtà, io consiglio di guardare l'intero Convert
Classe .
Questa classe, e molte altre classi utili sono parte della System
Namespace . Trovo utile per la scansione di quel namespace ogni anno o giù di lì per vedere cosa caratteristiche che ho perso. Provatelo!
Ho notato un sacco di persone stanno suggerendo Convert.ChangeType
- Questo funziona per alcuni casi, tuttavia, non appena si inizia a coinvolgere i tipi nullable
si inizierà a ricevere InvalidCastExceptions
:
Un wrapper è stato scritto alcuni anni fa per gestire questo, ma che non è perfetto sia.
È possibile utilizzare un convertitore di tipi (senza controllo degli errori):
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 termini di organizzazione del codice, è possibile creare un tipo-di mixin che si tradurrebbe in codice come questo:
Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");
Questo potrebbe essere raggiunto con questo codice:
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
può essere riutilizzata per molte classi diverse.
È anche possibile creare il proprio personalizzato convertitori di tipi per attaccare alle proprietà o classi:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Ho cercato la risposta da LBushkin e ha funzionato grande, ma non funziona per i valori nulli e campi Null. Così ho cambiato in questo modo:
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);
}
Probabilmente stai cercando il href="http://msdn.microsoft.com/en-us/library/dtb69x08.aspx" rel="noreferrer"> Convert.ChangeType
metodo . Ad esempio:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Utilizzando Convert.ChangeType
e ottenere il tipo di convertire dal PropertyInfo.PropertyType
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
risponderò questo con una risposta generale. Di solito queste risposte non si lavora con GUID. Ecco una versione di lavoro con GUID troppo.
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);
Oppure si potrebbe provare:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Se si sta scrivendo Metro app, è necessario utilizzare altro codice:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));
Nota:
ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
anziché
ship.GetType().GetProperty("Latitude");
utilizzando il seguente codice dovrebbe risolvere il problema:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
Stai cercando di giocare con la riflessione o stai cercando di costruire un pezzo produzione di software? Mi chiedo perché si sta utilizzando la riflessione per impostare una proprietà.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;