Impostare le proprietà dell’oggetto utilizzando la reflection

C’è un modo in C# in cui posso utilizzare la reflection per impostare una proprietà di un oggetto?

Ex:

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

Voglio impostare obj.Name con la riflessione. Qualcosa come:

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

C’è un modo di fare questo?

InformationsquelleAutor Melursus | 2009-03-06

 

10 Replies
  1. 362

    Sì, è possibile utilizzare Type.InvokeMember():

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

    Questo genererà un’eccezione se obj non hanno una proprietà chiamata Name, o non può essere impostato.

    Un altro approccio è quello di ottenere i metadati della proprietà, e quindi impostare. Questo vi permetterà di verificare l’esistenza della proprietà e verificare che è possibile impostare:

    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);
    }
    • Se non trattare con tutte le stringhe che si potrebbe desiderare di convertire i dati prima: var val = Convert.ChangeType(propValue, propInfo.PropertyType); fonte: devx.com/vb2themax/Tip/19599
    • in alternativa, è possibile utilizzare obj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
    • impossibile impostare il valore per CanWrite=False tipi, giusto?
    • sì, è corretto
  2. 267

    Si può anche fare:

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

    cui obiettivo è l’oggetto che avrà il suo set di proprietà.

    • Ho fatto la stessa cosa oggi. Sopra funziona alla grande, ovviamente null controllo dovrebbe essere fatto su prop prima di tentare di usarlo.
    • Io penso che ci si vuole sapere se si sta invocando la proprietà non valido, quindi, “non silenzio” sembra una cattiva corso.
    • Posso vedere il tuo punto, ma dipende dalla situazione davvero.
  3. 86

    Riflessione, in fondo, cioè

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

    o ci sono librerie per aiutare sia in termini di comodità e prestazioni; per esempio con FastMember:

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

    (che ha anche il vantaggio di non aver bisogno di sapere in anticipo se si tratta di un campo di vs proprietà)

    • Wow, ha un po ‘ confuso dall’unione, ma ho trovato la tua risposta di nuovo! Grazie, ti meriti un ‘accetta’, ma dato che il mio thread è fusa 🙁 Grazie ancora!
    • scusate per la confusione
    • Stavo guardando FastMember ed è piuttosto interessante. C’è una guida introduttiva/tutorial da qualche parte per noi comuni mortali per utilizzare questa grande lib di tuo?
    • Come posso ottenere il tipo di proprietà da parte di FastMember?
    • funzione di accesso => GetMembers => Member => Tipo di
    • grande risposta!!! La cosa buona di una oneliner è che è molto più veloce per capire, dato che non ci sono nessun utente denominato variabili tra che per te potrebbe non avere senso..

  4. 25

    O si può avvolgere Marc one liner all’interno della vostra estensione di classe:

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

    e di chiamare le cose come questo:

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

    Per buona misura, aggiungiamo un metodo per ottenere un valore di proprietà:

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

    Sì, utilizzando System.Reflection:

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

    È anche possibile accedere ai campi utilizzando un simillar modo:

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

    Con la riflessione, tutto può essere un libro aperto:) Nel mio esempio ci sono vincolanti per un’istanza privata a livello di campo.

  7. 11

    Utilizzare qualcosa di simile a questo :

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

    o

    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);
       }
    }
    • La parte in cui si ottiene il tipo di proprietà e poi il cast è stato davvero utile per me. Funziona come un fascino. Grazie
  8. 8

    Si può provare questo fuori quando si desidera di massa-assegnare le proprietà di un Oggetto da un altro Oggetto, utilizzando nomi di Proprietà:

    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;
                }
            }
        }
    }
    • Ciao e benvenuto per Stack Overflow. Si prega di formattare il codice correttamente, e non solo il dump in un tuo post, aiuterà gli altri a capire la tua risposta.
  9. 0

    Ho appena pubblicato un pacchetto Nuget che consente di impostare non solo il primo livello di Proprietà, ma anche nidificate proprietà in oggetto dato in qualsiasi profondità.

    Qui è il pacchetto

    Imposta il valore di una proprietà di un oggetto dal suo percorso dalla radice.

    L’oggetto può essere un oggetto complesso e la struttura può essere a più livelli di profondità proprietà nidificate o può essere una proprietà direttamente sotto la root. ObjectWriter trovare la struttura, utilizzando le proprietà parametro percorso e aggiornare il suo valore. La struttura del percorso è aggiunto, i nomi delle proprietà visitato dalla radice alla fine il nodo della proprietà che si desidera impostare, delimitato dal delimitatore di stringa parametro.

    Uso:

    Per l’impostazione delle proprietà direttamente al di sotto dell’oggetto principale:

    Ie. LineItem classe ha un int proprietà denominata ItemId

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

    Per l’impostazione di proprietà nidificate più livelli al di sotto dell’oggetto principale:

    Ie. Invite classe ha una proprietà chiamata State, che ha una proprietà chiamata Invite (di Invitare tipo), che ha una proprietà chiamata Recipient, che ha una proprietà chiamata Id.

    Per rendere le cose ancora più complesse, il State proprietà non è un tipo di riferimento, è un struct.

    Qui è come si può impostare l’Id di proprietà (valore stringa di “outlook”) in fondo l’albero di oggetti in una singola riga.

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

    Base MarcGravell suggerimento, ho costruito il seguente metodo statico.Il metodo genericamente assegna a tutti gli immobili da fonte oggetto di destinazione utilizzando 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);
                }
            }
        }

Lascia un commento