340 votes

Définir une propriété par réflexion avec une valeur de type chaîne

Je voudrais définir une propriété d'un objet via la réflexion, 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 je voudrais faire:

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

Tel quel, cela génère une ArgumentException:

Object de type 'System.String' ne peut pas être converti en type 'System.Double'.

Comment puis-je convertir la valeur au type approprié, en fonction de propertyInfo?

1 votes

Question pour vous: est-ce que cela fait partie d'une solution ORM personnalisée?

567voto

LBushkin Points 60611

Vous pouvez utiliser Convert.ChangeType() - Cela vous permet d'utiliser les informations d'exécution sur n'importe quel type IConvertible pour changer les formats de représentation. Cependant, toutes les conversions ne sont pas possibles et vous devrez peut-être écrire une logique de cas spécial si vous souhaitez prendre en charge des conversions à partir de types qui ne sont pas IConvertible.

Le code correspondant (sans gestion d'exceptions ou logique de cas spécial) serait:

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

0 votes

Veuillez examiner la réponse de @AliKaraca ci-dessous. Les deux réponses, celle-ci et celle ci-dessous, sont rapides et approximatives mais font l'affaire pour les types courants.

0 votes

Y a-t-il un TryChangeType ou CanChangeType?

35voto

John Saunders Points 118808

Comme plusieurs l'ont déjà dit, vous voulez utiliser Convert.ChangeType:

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

En fait, je vous recommande de regarder l'ensemble de la Classe Convert.

Cette classe, ainsi que de nombreuses autres classes utiles, font partie de l'Espace de noms System. Je trouve utile de parcourir cet espace de noms chaque année environ pour voir quelles fonctionnalités j'ai manquées. Essayez-le!

1 votes

Le OP veut probablement la réponse générale, pour définir une propriété de n'importe quel type qui a une conversion évidente à partir d'une chaîne.

0 votes

Bon point. Je vais modifier et orienter vers les vrais répondants, ou je supprimerai le mien si quelqu'un ajoute ce que j'ai dit sur le reste de l'espace de noms.

20voto

Shahin Points 1968

Je remarque que beaucoup de gens recommandent Convert.ChangeType - Cela fonctionne pour certains cas, cependant dès que vous commencez à inclure des types nullable vous commencerez à recevoir des 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

12voto

Jordão Points 29221

Vous pouvez utiliser un convertisseur de type (aucune 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 pourriez créer une sorte de mixin qui aboutirait à un code semblable à ceci:

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

Cela 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 de nombreuses classes différentes.

Vous pouvez également créer vos propres convertisseurs de type personnalisés à attacher à vos propriétés ou classes:

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

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

0 votes

Y a-t-il une raison particulière pour laquelle vous avez ajouté l'interface de marqueur au lieu d'utiliser simplement object?

1 votes

Oui, l'interface de marqueur sert de placeholder pour ajouter des méthodes d'extension. Utiliser object ajouterait les méthodes d'extension à toutes les classes, ce qui n'est généralement pas souhaitable.

6voto

John Calsbeek Points 19381

Vous êtes probablement à la recherche de 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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X