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




attribut set (9)

Je voudrais définir une propriété d'un objet via Reflection, avec une valeur de type string . Ainsi, 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);

En l'état, cela déclenche une ArgumentException :

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

Comment est-ce que je peux convertir la valeur au type approprié, basé sur propertyInfo ?


Answers

Vous pouvez utiliser Convert.ChangeType() - Il vous permet d'utiliser des informations d'exécution sur n'importe IConvertible 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 spéciale si vous souhaitez prendre en charge les conversions provenant de types qui ne sont pas IConvertible .

Le code correspondant (sans manipulation d'exception ou 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);

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

Cherchez-vous à jouer avec Reflection ou cherchez-vous à construire un logiciel de production? Je voudrais savoir pourquoi vous utilisez la réflexion pour définir une propriété.

Double new_latitude;

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

J'ai essayé la réponse de LBushkin et cela a fonctionné très bien, mais cela ne fonctionnera pas pour les valeurs nulles et les champs nullables. Donc je l'ai changé à 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);
}

Ou vous pouvez essayer:

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

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

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 pouvez créer une sorte de mixin qui aboutirait à un code comme celui-ci:

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 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 { ... }

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 de regarder l'ensemble de la classe Convert .

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


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

Je cherchais quelque chose de similaire moi-même, de préférence sans utiliser une bibliothèque ou trier toute la liste. Ma solution a fini par ressembler à la question elle-même, juste un peu simplifiée.

var firstBorn = People.FirstOrDefault(p => p.DateOfBirth == People.Min(p2 => p2.DateOfBirth));






c# reflection type-conversion propertyinfo setvalue