it-swarm.com.de

Festlegen der Objekteigenschaft mithilfe der Reflexion

Gibt es in C # eine Möglichkeit, mit Reflection eine Objekteigenschaft festzulegen?

Ex:

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

Ich möchte obj.Name mit Reflektion. So etwas wie:

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

Gibt es eine Möglichkeit, dies zu tun?

299
Melursus

Ja, Sie können Type.InvokeMember() verwenden:

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

Dies löst eine Ausnahme aus, wenn obj keine Eigenschaft mit dem Namen Name hat oder nicht festgelegt werden kann.

Ein anderer Ansatz besteht darin, die Metadaten für die Eigenschaft abzurufen und dann festzulegen. Auf diese Weise können Sie überprüfen, ob die Eigenschaft vorhanden ist und ob sie festgelegt werden kann:

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);
}
364
Andy

Sie können auch:

Type type = target.GetType();

PropertyInfo prop = type.GetProperty("propertyName");

prop.SetValue (target, propertyValue, null);

dabei ist Ziel das Objekt, für das die Eigenschaft festgelegt wird.

269
El Cheicon

Reflexion im Grunde genommen, d.h.

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

oder es gibt Bibliotheken, die sowohl in Bezug auf die Benutzerfreundlichkeit als auch in Bezug auf die Leistung hilfreich sind. zum Beispiel mit FastMember :

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

(was auch den Vorteil hat, nicht im Voraus wissen zu müssen, ob es sich um ein Feld oder eine Eigenschaft handelt)

86
Marc Gravell

Oder du wickelst Marc's einen Liner in deine eigene Erweiterungsklasse:

public static class PropertyExtension{       

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

und nenne es so:

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

Fügen Sie eine Methode hinzu, um einen Eigenschaftswert zu erhalten:

public static object GetPropertyValue(this object obj, string propName)
{
        return obj.GetType().GetProperty(propName).GetValue (obj, null);
}
26
Erik K.

Ja, mit System.Reflection:

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);
14
D Stanley

Sie können auf Felder auch auf ähnliche Weise zugreifen:

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

Mit Reflection kann alles ein offenes Buch sein :) In meinem Beispiel sind wir an ein Feld auf privater Instanzebene gebunden.

12
JoshBerke

Benutze so etwas:

public static class PropertyExtension{       

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

oder

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string 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);
   }
}
11

Sie können dies ausprobieren, wenn Sie Eigenschaften eines Objekts mithilfe von Eigenschaftsnamen einem anderen Objekt massenweise zuweisen möchten:

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;
            }
        }
    }
}
8
user3679106

Ich habe gerade ein Nuget-Paket veröffentlicht, mit dem Sie nicht nur die Eigenschaften der ersten Ebene, sondern auch verschachtelte Eigenschaften in dem angegebenen Objekt in beliebiger Tiefe einrichten können.

Hier ist das Paket

Legt den Wert einer Eigenschaft eines Objekts anhand seines Pfads vom Stamm aus fest.

Das Objekt kann ein komplexes Objekt sein und die Eigenschaft kann eine tief verschachtelte Eigenschaft mit mehreren Ebenen oder eine Eigenschaft direkt unter dem Stamm sein. ObjectWriter findet die Eigenschaft mithilfe des Eigenschaftspfadparameters und aktualisiert ihren Wert. Der Eigenschaftspfad besteht aus den angehängten Namen der Eigenschaften, die vom Stammknoten bis zur Endknoteneigenschaft besucht werden und die durch den Begrenzerzeichenfolge-Parameter getrennt werden sollen.

Verwendungszweck:

So richten Sie die Eigenschaften direkt unter dem Objektstamm ein:

Dh LineItem Klasse hat eine int-Eigenschaft namens ItemId

LineItem lineItem = new LineItem();

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

Zum Einrichten verschachtelter Eigenschaften auf mehreren Ebenen unter dem Objektstamm:

Dh Invite Klasse hat eine Eigenschaft namens State, die eine Eigenschaft namens Invite (vom Typ Invite) hat, die eine Eigenschaft namens Recipient hat, die a hat Eigenschaft namens Id.

Um die Dinge noch komplexer zu gestalten, ist die Eigenschaft State kein Referenztyp, sondern ein struct.

Hier erfahren Sie, wie Sie die Id-Eigenschaft (auf den Zeichenfolgenwert von "Outlook") am unteren Rand des Objektbaums in einer einzelnen Zeile festlegen können.

Invite invite = new Invite();

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "Outlook", delimiter: "_");
0
Dogu Arslan

Auf der Grundlage von MarcGravells Vorschlag habe ich die folgende statische Methode erstellt. Die Methode generisch weist alle übereinstimmenden Eigenschaften vom Quellobjekt zum Ziel zu, indem sie FastMember verwendet

 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);
            }
        }
    }
0
Cogent