web-dev-qa-db-fra.com

Définition d'une propriété par réflexion avec une valeur de chaîne

J'aimerais définir une propriété d'un objet via Reflection, avec une valeur de type string. Donc, par exemple, supposons que j'ai une classe Ship, avec une propriété de Latitude, qui est un double.

Voici ce que j'aimerais faire:

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

Tel quel, cela jette un ArgumentException:

Les objets de type 'System.String' ne peuvent pas être convertis en type 'System.Double'.

Comment puis-je convertir la valeur en un type approprié, basé sur propertyInfo?

291
David Hodgson

Vous pouvez utiliser Convert.ChangeType() - Il vous permet d'utiliser les informations d'exécution sur tout type IConvertible pour modifier les formats de représentation. Cependant, toutes les conversions ne sont pas possibles et vous devrez peut-être écrire une logique de casse particulière si vous souhaitez prendre en charge les conversions provenant de types non IConvertible.

Le code correspondant (sans traitement des exceptions ni logique de cas particulier) serait:

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

Comme plusieurs autres l'ont dit, vous voulez utiliser Convert.ChangeType:

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

En fait, je vous recommande d’examiner l’ensemble Convert Class .

Cette classe et de nombreuses autres classes utiles font partie de System Namespace . Je trouve utile d'analyser cet espace de noms tous les ans environ pour voir les fonctionnalités que j'ai manquées. Essaie!

33
John Saunders

Je remarque que beaucoup de gens recommandent Convert.ChangeType - Cela fonctionne dans certains cas, mais dès que vous commencez à utiliser les types nullable, vous commencerez à recevoir InvalidCastExceptions:

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

Un wrapper a été écrit il y a quelques années pour gérer cela, mais ce n'est pas parfait non plus.

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

19
Tablet

Vous pouvez utiliser un convertisseur de type (pas de vérification d'erreur):

Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);

En termes d'organisation du code, vous pouvez créer un type de mixin qui donnerait le code suivant:

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

Ceci serait réalisé avec ce 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 peut être réutilisé pour différentes classes.

Vous pouvez également créer votre propre personnalisation convertisseurs de type à attacher à vos propriétés ou classes:

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

[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
11
Jordão

J'ai essayé la réponse de LBushkin et cela a bien fonctionné, mais cela ne fonctionnera pas pour les valeurs NULL et les champs Nullable. Donc je l'ai changé en ceci:

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);
}
9
Ashkan Sirous

Vous recherchez probablement la méthode Convert.ChangeType . Par exemple:

_Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
_
6
John Calsbeek

Utiliser Convert.ChangeType et obtenir le type à convertir à partir de PropertyInfo.PropertyType.

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

Je vais répondre à cela avec une réponse générale. Habituellement, ces réponses ne fonctionnent pas avec des guides. Voici une version de travail avec des guides aussi.

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); 
4
Ali Karaca

Ou vous pouvez essayer:

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

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

Si vous écrivez l'application Metro, vous devez utiliser un autre code:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));

Remarque:

ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");

au lieu de

ship.GetType().GetProperty("Latitude");
2
Serhiy

L'utilisation du code suivant devrait résoudre votre problème:

item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
0
Marco Sotto