Je veux convertir une chaîne en une valeur de propriété d’object, dont le nom est une chaîne. J’essaie de faire comme ça:
ssortingng modelProperty = "Some Property Name"; ssortingng value = "SomeValue"; var property = entity.GetType().GetProperty(modelProperty); if (property != null) { property.SetValue(entity, Convert.ChangeType(value, property.PropertyType), null); }
Le problème est que cela échoue et lance une exception de conversion non valide lorsque le type de propriété est un type nullable. Ce n’est pas le cas si les valeurs ne peuvent pas être converties – elles fonctionneront si je le fais manuellement (par exemple DateTime? d = Convert.ToDateTime(value);
) J’ai vu des questions similaires mais je ne peux toujours pas l’obtenir travailler.
Non testé, mais peut-être que quelque chose comme ça fonctionnera:
ssortingng modelProperty = "Some Property Name"; ssortingng value = "Some Value"; var property = entity.GetType().GetProperty(modelProperty); if (property != null) { Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; object safeValue = (value == null) ? null : Convert.ChangeType(value, t); property.SetValue(entity, safeValue, null); }
Vous devez obtenir le type sous-jacent pour faire cela …
Essayez ceci, je l’ai utilisé avec succès avec des génériques:
//Coalesce to get actual property type... Type t = property.PropertyType(); t = Nullable.GetUnderlyingType(t) ?? t; //Coalesce to set the safe value using default(t) or the safe type. safeValue = value == null ? default(t) : Convert.ChangeType(value, t);
Je l’utilise à plusieurs endroits dans mon code, par exemple, une méthode d’assistance que j’utilise pour convertir des valeurs de firebase database de manière sécurisée:
public static T GetValue(this IDataReader dr, ssortingng fieldName) { object value = dr[fieldName]; Type t = typeof(T); t = Nullable.GetUnderlyingType(t) ?? t; return (value == null || DBNull.Value.Equals(value)) ? default(T) : (T)Convert.ChangeType(value, t); }
Appelé en utilisant:
ssortingng field1 = dr.GetValue("field1"); int? field2 = dr.GetValue("field2"); DateTime field3 = dr.GetValue("field3");
J’ai écrit une série d’articles de blog, y compris à l’ adresse suivante : http://www.endswithsaurus.com/2010_07_01_archive.html (Faites défiler jusqu’à l’addendum, @JohnMacintyre a en fait repéré le bogue dans mon code d’origine, ce qui m’a conduit à suivre le même chemin que vous.) maintenant). J’ai quelques petites modifications depuis cet article qui inclut la conversion des types enum aussi, donc si votre propriété est un Enum, vous pouvez toujours utiliser le même appel de méthode. Ajoutez simplement une ligne pour vérifier les types d’énumération et vous partez pour les courses en utilisant quelque chose comme:
if (t.IsEnum) return (T)Enum.Parse(t, value);
Normalement, vous devriez vérifier certaines erreurs ou utiliser TryParse au lieu de Parse, mais vous obtenez l’image.
Ceci est un peu long pour un exemple, mais il s’agit d’une approche relativement robuste qui sépare la tâche de conversion de valeur inconnue en type inconnu.
J’ai une méthode TryCast qui fait quelque chose de similaire et prend en compte les types nullables.
public static bool TryCast(this object value, out T result) { var type = typeof (T); // If the type is nullable and the result should be null, set a null value. if (type.IsNullable() && (value == null || value == DBNull.Value)) { result = default(T); return true; } // Convert.ChangeType fails on Nullable types. We want to try to cast to the underlying type anyway. var underlyingType = Nullable.GetUnderlyingType(type) ?? type; try { // Just one edge case you might want to handle. if (underlyingType == typeof(Guid)) { if (value is ssortingng) { value = new Guid(value as ssortingng); } if (value is byte[]) { value = new Guid(value as byte[]); } result = (T)Convert.ChangeType(value, underlyingType); return true; } result = (T)Convert.ChangeType(value, underlyingType); return true; } catch (Exception ex) { result = default(T); return false; } }
Bien sûr, TryCast est une méthode avec un paramètre de type, donc pour l’appeler dynamicment, vous devez vous-même construire MethodInfo:
var constructedMethod = typeof (ObjectExtensions) .GetMethod("TryCast") .MakeGenericMethod(property.PropertyType);
Ensuite, pour définir la valeur de la propriété réelle:
public static void SetCastedValue(this PropertyInfo property, T instance, object value) { if (property.DeclaringType != typeof(T)) { throw new ArgumentException("property's declaring type must be equal to typeof(T)."); } var constructedMethod = typeof (ObjectExtensions) .GetMethod("TryCast") .MakeGenericMethod(property.PropertyType); object valueToSet = null; var parameters = new[] {value, null}; var tryCastSucceeded = Convert.ToBoolean(constructedMethod.Invoke(null, parameters)); if (tryCastSucceeded) { valueToSet = parameters[1]; } if (!property.CanAssignValue(valueToSet)) { return; } property.SetValue(instance, valueToSet, null); }
Et les méthodes d’extension pour gérer property.CanAssignValue …
public static bool CanAssignValue(this PropertyInfo p, object value) { return value == null ? p.IsNullable() : p.PropertyType.IsInstanceOfType(value); } public static bool IsNullable(this PropertyInfo p) { return p.PropertyType.IsNullable(); } public static bool IsNullable(this Type t) { return !t.IsValueType || Nullable.GetUnderlyingType(t) != null; }
J’ai eu un besoin similaire, et la réponse de LukeH m’a orienté dans la direction. Je suis venu avec cette fonction générique pour le rendre facile.
public static Tout CopyValue(Tin from, Tout toPrototype) { Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout)); if (underlyingT == null) { return (Tout)Convert.ChangeType(from, typeof(Tout)); } else { return (Tout)Convert.ChangeType(from, underlyingT); } }
L’utilisation est comme ceci:
NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);
Notez que le second paramètre est simplement utilisé comme prototype pour montrer à la fonction comment convertir la valeur de retour, de sorte qu’elle ne doit pas nécessairement être la propriété de destination. Ce qui signifie que vous pouvez faire aussi quelque chose comme ceci:
DateTime? source = new DateTime(2015, 1, 1); var dest = CopyValue(source, (ssortingng)null);
Je l’ai fait de cette façon au lieu d’utiliser un out car vous ne pouvez pas utiliser les propriétés. Tel quel, il peut fonctionner avec des propriétés et des variables. Vous pouvez également créer une surcharge pour passer le type à la place si vous le souhaitez.
Merci @ LukeH
J’ai un peu changé:
public static object convertToPropType(PropertyInfo property, object value) { object cstVal = null; if (property != null) { Type propType = Nullable.GetUnderlyingType(property.PropertyType); bool isNullable = (propType != null); if (!isNullable) { propType = property.PropertyType; } bool canAtsortingb = (value != null || isNullable); if (!canAtsortingb) { throw new Exception("Cant atsortingb null on non nullable. "); } cstVal = (value == null || Convert.IsDBNull(value)) ? null : Convert.ChangeType(value, propType); } return cstVal; }