Définir la propriété d’object en utilisant la reflection

Existe-t-il un moyen dans C # 3.5 où je peux utiliser la reflection pour définir une propriété d’object?

Ex:

MyObject obj = new MyObject(); obj.Name = "Value"; 

Je veux définir obj.Name avec reflection. Quelque chose comme:

 Reflection.SetProperty(obj, "Name") = "Value"; 

Y-a-t’il une façon de le faire?

Oui, vous pouvez utiliser Type.InvokeMember() :

 using System.Reflection; MyObject obj = new MyObject(); obj.GetType().InvokeMember("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, Type.DefaultBinder, obj, "Value"); 

Cela jettera une exception si obj n’a pas de propriété appelée Name , ou il ne peut pas être défini.

Une autre approche consiste à obtenir les métadonnées de la propriété, puis à la définir. Cela vous permettra de vérifier l’existence de la propriété et de vérifier qu’elle peut être définie:

 using System.Reflection; MyObject obj = new MyObject(); PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); if(null != prop && prop.CanWrite) { prop.SetValue(obj, "Value", null); } 

Vous pouvez aussi faire:

 Type type = target.GetType(); PropertyInfo prop = type.GetProperty("propertyName"); prop.SetValue (target, propertyValue, null); 

où target est l’object qui aura son jeu de propriétés.

Réflexion, en gros, c.-à-d.

 myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null); 

ou il existe des bibliothèques pour aider à la fois en termes de commodité et de performance; par exemple avec FastMember :

 var wrapped = ObjectAccessor.Create(obj); wrapped[property] = "Bob"; 

(qui a aussi l’avantage de ne pas avoir besoin de savoir à l’avance s’il s’agit d’un champ ou d’une propriété)

Ou vous pourriez envelopper un paquebot de Marc dans votre propre classe d’extension:

 public static class PropertyExtension{ public static void SetPropertyValue(this object obj, ssortingng propName, object value) { obj.GetType().GetProperty(propName).SetValue(obj, value, null); } } 

et appelez comme ceci:

 myObject.SetPropertyValue("myProperty", "myValue"); 

Pour faire bonne mesure, ajoutons une méthode pour obtenir une valeur de propriété:

 public static object GetPropertyValue(this object obj, ssortingng propName) { return obj.GetType().GetProperty(propName).GetValue (obj, null); } 

Oui, en utilisant System.Reflection :

 using System.Reflection; ... ssortingng prop = "name"; PropertyInfo pi = myObject.GetType().GetProperty(prop); pi.SetValue(myObject, "Bob", null); 

Vous pouvez également accéder aux champs de manière simillar:

 var obj=new MyObject(); FieldInfo fi = obj.GetType(). GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance); fi.SetValue(obj,value) 

Avec la reflection, tout peut être un livre ouvert 🙂 Dans mon exemple, nous sums liés à un champ de niveau instance privée.

Utilisez des choses comme ceci:

 public static class PropertyExtension{ public static void SetPropertyValue(this object p_object, ssortingng p_propertyName, object value) { PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null); } } 

ou

 public static class PropertyExtension{ public static void SetPropertyValue(this object p_object, ssortingng p_propertyName, object value) { PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; object safeValue = (value == null) ? null : Convert.ChangeType(value, t); property.SetValue(p_object, safeValue, null); } } 

Vous pouvez essayer ceci lorsque vous souhaitez assigner en masse les propriétés d’un object à partir d’un autre object en utilisant les noms de propriété:

 public static void Assign(this object destination, object source) { if (destination is IEnumerable && source is IEnumerable) { var dest_enumerator = (destination as IEnumerable).GetEnumerator(); var src_enumerator = (source as IEnumerable).GetEnumerator(); while (dest_enumerator.MoveNext() && src_enumerator.MoveNext()) dest_enumerator.Current.Assign(src_enumerator.Current); } else { var destProperties = destination.GetType().GetProperties(); foreach (var sourceProperty in source.GetType().GetProperties()) { foreach (var destProperty in destProperties) { if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType)) { destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }), new object[] { }); break; } } } } 

Je viens de publier un package Nuget qui permet de configurer non seulement les propriétés de premier niveau, mais aussi les propriétés nestedes dans l’object donné, quelle que soit sa profondeur.

Voici le package

Définit la valeur d’une propriété d’un object par son chemin depuis la racine.

L’object peut être un object complexe et la propriété peut être une propriété nestede à plusieurs niveaux ou une propriété directement sous la racine. ObjectWriter trouvera la propriété en utilisant le paramètre de chemin de propriété et mettra à jour sa valeur. Le chemin de propriété est le nom ajouté des propriétés visitées de la racine à la propriété de noeud final que nous voulons définir, délimitée par le paramètre de chaîne de délimiteur.

Usage:

Pour configurer les propriétés directement sous la racine de l’object:

C’est à dire. LineItem classe LineItem a une propriété int appelée ItemId

 LineItem lineItem = new LineItem(); ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null); 

Pour configurer des propriétés nestedes à plusieurs niveaux sous la racine de l’object:

C’est à dire. Invite classe Invite a une propriété appelée State , qui possède une propriété appelée Invite (de type Invite), qui possède une propriété appelée Recipient , qui possède une propriété appelée Id .

Pour rendre les choses encore plus complexes, la propriété State n’est pas un type de référence, c’est une struct .

Voici comment vous pouvez définir la propriété Id (à la valeur de chaîne de “outlook”) au bas de l’arborescence des objects sur une seule ligne.

 Invite invite = new Invite(); ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_"); 

Sur la base de la suggestion de MarcGravell, j’ai construit la méthode statique suivante. La méthode assigne de manière générique toutes les propriétés correspondantes d’un object source à la cible en utilisant FastMember.

  public static void DynamicPropertySet(object source, object target) { //SOURCE var src_accessor = TypeAccessor.Create(source.GetType()); if (src_accessor == null) { throw new ApplicationException("Could not create accessor!"); } var src_members = src_accessor.GetMembers(); if (src_members == null) { throw new ApplicationException("Could not fetch members!"); } var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); var src_class_propNames = src_class_members.Select(x => x.Name); var src_propNames = src_members.Except(src_class_members).Select(x => x.Name); //TARGET var trg_accessor = TypeAccessor.Create(target.GetType()); if (trg_accessor == null) { throw new ApplicationException("Could not create accessor!"); } var trg_members = trg_accessor.GetMembers(); if (trg_members == null) { throw new ApplicationException("Could not create accessor!"); } var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); var trg_class_propNames = trg_class_members.Select(x => x.Name); var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name); var class_propNames = trg_class_propNames.Intersect(src_class_propNames); var propNames = trg_propNames.Intersect(src_propNames); foreach (var propName in propNames) { trg_accessor[target, propName] = src_accessor[source, propName]; } foreach (var member in class_propNames) { var src = src_accessor[source, member]; var trg = trg_accessor[target, member]; if (src != null && trg != null) { DynamicPropertySet(src, trg); } } }