‘casting’ avec reflection

Considérez l’exemple de code suivant:

class SampleClass { public long SomeProperty { get; set; } } public void SetValue(SampleClass instance, decimal value) { // value is of type decimal, but is in reality a natural number => cast instance.SomeProperty = (long)value; } 

Maintenant, je dois faire quelque chose de similaire en réfléchissant:

 void SetValue(PropertyInfo info, object instance, object value) { // throws System.ArgumentException: Decimal can not be converted to Int64 info.SetValue(instance, value) } 

Notez que je ne peux pas supposer que le PropertyInfo représente toujours un long, ni cette valeur est toujours un décimal. Cependant, je sais que cette valeur peut être convertie au type correct pour cette propriété.

Comment convertir le paramètre ‘value’ dans le type représenté par l’occurrence de PropertyInfo par reflection?

 void SetValue(PropertyInfo info, object instance, object value) { info.SetValue(instance, Convert.ChangeType(value, info.PropertyType)); } 

La réponse de Thomas a raison, mais je pensais append ma conclusion que Convert.ChangeType ne gère pas la conversion en types nullables. Pour gérer les types nullables, j’ai utilisé le code suivant:

 void SetValue(PropertyInfo info, object instance, object value) { var targetType = info.PropertyType.IsNullableType() ? Nullable.GetUnderlyingType(info.PropertyType) : info.PropertyType; var convertedValue = Convert.ChangeType(value, targetType); info.SetValue(instance, convertedValue, null); } 

Ce code utilise la méthode d’extension suivante:

 public static class TypeExtensions { public static bool IsNullableType(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); } 

La réponse de Thomas ne fonctionne que pour les types qui implémentent l’interface IConvertible:

Pour que la conversion réussisse, value doit implémenter l’interface IConvertible, car la méthode encapsule simplement un appel à une méthode IConvertible appropriée. La méthode nécessite que la conversion de valeur en conversionType soit prise en charge.

Ce code comstack une expression linq qui fait le unboxing (si nécessaire) et la conversion:

  public static object Cast(this Type Type, object data) { var DataParam = Expression.Parameter(typeof(object), "data"); var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type)); var Run = Expression.Lambda(Body, DataParam).Comstack(); var ret = Run.DynamicInvoke(data); return ret; } 

L’expression lambda obtenue est égale à (TOut) (TIn) Données où TIn est le type des données d’origine et TOut est le type donné

En consortingbuant à la réponse de jeroenh, j’appendais que Convert.ChangeType se bloque avec une valeur nulle, donc la ligne pour obtenir la valeur convertie doit être:

 var convertedValue = value == null ? null : Convert.ChangeType(value, targetType); 

Lorsque le Type est un Guid Nullable, aucune des solutions proposées ci-dessus ne fonctionne. La dissortingbution invalide de l’exception System.DBNull à System.Guid est lancée sur Convert.ChangeType

Pour corriger ce changement, procédez comme suit:

 var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);