Frage

Gibt es eine Möglichkeit in C #, wo ich Reflektion verwenden kann, eine Objekteigenschaft zu setzen?

Beispiel:

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

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

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

Gibt es eine Möglichkeit, dies zu tun?

War es hilfreich?

Lösung

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

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

Das wird eine Ausnahme ausgelöst, wenn obj keine Eigenschaft namens Name hat, oder es kann nicht eingestellt werden.

Ein weiterer Ansatz ist die Metadaten für die Immobilie zu erhalten, und legen Sie es dann. Dies ermöglicht es Ihnen für die Existenz des Eigentums zu überprüfen und sicherzustellen, dass es eingestellt 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);
}

Andere Tipps

Sie können auch tun:

Type type = target.GetType();

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

prop.SetValue (target, propertyValue, null);

Dabei Ziel ist das Objekt, das seine Eigenschaft festgelegt hat.

Spiegelung, im Grunde, d.

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

oder gibt es Bibliotheken sowohl in Bezug auf Komfort und Leistung zu helfen; 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 gegen eine Eigenschaft ist)

Oder Sie könnten einen Liner innerhalb Ihrer eigenen Nebenklasse wickeln Marc:

public static class PropertyExtension{       

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

und nennen Sie es wie folgt aus:

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

Für eine gute Maßnahme, lassen Sie uns eine Methode fügen Sie einen Eigenschaftswert zu erhalten:

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

Ja, mit System.Reflection:

using System.Reflection;

...

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

Sie können auch Zugriff auf Felder eine ähnliche Art und Weise mit:

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

Mit Reflexion allem kann ein offenes Buch sein :) In meinem Beispiel wir zu einem privaten Instanzebene Feld sind verbindlich.

Verwenden Somethings wie folgt aus:

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

Sie können dies ausprobieren, wenn Sie die Massen assign Eigenschaften eines Objekts von einem anderen Objekt mit Eigenschaftsnamen wollen:

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

Ich habe gerade ein Nuget Paket veröffentlicht, das nicht nur die erste Ebene Eigenschaften ermöglicht die Einrichtung, sondern auch im gegebenen Objekt in beliebiger Tiefe verschachtelt Eigenschaften.

Hier ist das Paket

Setzt den Wert einer Eigenschaft eines Objekts von seinem Weg von der Wurzel.

Das Objekt kann ein komplexes Objekt sein und die Eigenschaft kann auf mehrere Ebenen tief verschachtelte Eigenschaft sein, oder es kann eine Eigenschaft direkt unter der Wurzel sein. ObjectWriter wird die Eigenschaft mit der Eigenschaft Pfad Parametern finden und seinen Wert aktualisieren. Eigenschaftenpfad ist die beigefügten Namen der Eigenschaften von der Wurzel bis zum Endknoten Objekt besucht haben, die wir einstellen wollen, begrenzt durch den Begrenzer String-Parameter.

Verbrauch:

Für die Eigenschaften direkt unter dem Wurzelobjekt einrichten:

Ie. LineItem Klasse hat eine Eigenschaft namens int ItemId

LineItem lineItem = new LineItem();

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

Für verschachtelte Eigenschaft mehrere Ebenen unterhalb des Wurzelobjekt einrichten:

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

Um die Dinge noch komplizierter zu machen, wird die State Eigenschaft kein Referenztyp, es ist ein struct.

Hier ist, wie Sie die Id-Eigenschaft (auf String-Wert „outlook“) am unteren Rande des Objektbaums in einer einzigen Zeile setzen.

Invite invite = new Invite();

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

Basierend auf MarcGravell Vorschlag, habe ich folgende statische Verfahren.Verfahren konstruierte generisch ordnet alle passenden Eigenschaften von Quellobjekt zum Ziel unter Verwendung von 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);
            }
        }
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top