Ustaw właściwość obiektu za pomocą odbicia

Czy Jest jakiś sposób w C# 3.5 gdzie mogę użyć reflection aby ustawić właściwość obiektu?

Ex:

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

Chcę ustawić obj.Name z refleksją. Coś w stylu:

Reflection.SetProperty(obj, "Name") = "Value";
Jest na to jakiś sposób?
Author: jpaugh, 2009-03-06

11 answers

Tak, możesz użyć Type.InvokeMember():

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

Spowoduje wyrzucenie wyjątku, jeśli obj nie ma właściwości o nazwie Name lub nie można jej ustawić.

Innym sposobem jest pobranie metadanych właściwości, a następnie jej ustawienie. To pozwoli Ci sprawdzić istnienie właściwości i sprawdzić, czy można ją ustawić:

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);
}
 327
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-09 20:22:06

Możesz również zrobić:

Type type = target.GetType();

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

prop.SetValue (target, propertyValue, null);

Gdzie target jest obiektem, który będzie miał ustawioną właściwość.

 246
Author: El Cheicon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 17:55:33

Odbicie, czyli w zasadzie

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

Lub istnieją biblioteki, które pomagają zarówno pod względem wygody, jak i wydajności; na przykład z FastMember :

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

(który również ma tę zaletę, że nie musi wiedzieć z góry, czy jest to pole a własność)

 79
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-20 14:05:09

Albo możesz owinąć jedną liner Marc ' a wewnątrz swojej własnej klasy extension:

public static class PropertyExtension{       

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

I nazwij to tak:

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

Dla dobrej miary, dodajmy metodę, aby uzyskać wartość właściwości:

public static object GetPropertyValue(this object obj, string propName)
{
        return obj.GetType().GetProperty(propName).GetValue (obj, null);
}
 23
Author: Erik K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-20 21:44:05

Tak, używając System.Reflection:

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);
 14
Author: D Stanley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 13:49:35

Możesz również uzyskać dostęp do pól używając simillar:

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

Z refleksją wszystko może być otwartą książką:) w moim przykładzie wiążemy się z prywatnym polem poziomu instancji.

 11
Author: JoshBerke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 18:00:20

Użyj czegoś takiego:

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

Lub

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);
   }
}
 10
Author: Ardalan Shahgholi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-03 10:11:01

Możesz to wypróbować, gdy chcesz masowo przypisać właściwości obiektu z innego obiektu za pomocą nazw właściwości:

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;
            }
        }
    }
}
 7
Author: user3679106,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-20 18:35:41

Właśnie opublikowałem pakiet Nuget, który umożliwia ustawienie nie tylko właściwości pierwszego poziomu, ale także właściwości zagnieżdżonych w danym obiekcie w dowolnej głębi.

Oto pakiet

Ustawia wartość właściwości obiektu według jego ścieżki z katalogu głównego.

Obiekt może być obiektem złożonym, a właściwość może być wielopoziomową, głęboką zagnieżdżoną właściwością lub może być właściwością bezpośrednio pod rootem. ObjectWriter znajdzie nieruchomość korzystając z nieruchomości parametr ścieżki i zaktualizuj jego wartość. Ścieżka właściwości to dołączone nazwy właściwości odwiedzanych od root do właściwości węzła końcowego, które chcemy ustawić, oddzielone przez parametr delimiter string.

Użycie:

Do Ustawienia Właściwości bezpośrednio pod głównym obiektem:

Ie. LineItem klasa ma właściwość int o nazwie ItemId

LineItem lineItem = new LineItem();

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

Do Ustawienia zagnieżdżonej właściwości wielu poziomów poniżej głównego obiektu:

Ie. Invite klasa ma właściwość o nazwie State, która ma właściwość o nazwie Invite (Typu Invite), która ma właściwość o nazwie Recipient, która ma właściwość o nazwie Id.

Aby uczynić rzeczy jeszcze bardziej złożonymi, właściwość State nie jest typem odniesienia, jest struct.

Oto jak można ustawić właściwość Id (na wartość string "outlook") na dole drzewa obiektów w jednej linii.

Invite invite = new Invite();

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");
 0
Author: Dogu Arslan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-24 18:25:15

Bazując na sugestii Marcgravella, skonstruowałem następującą metodę statyczną.Metoda ogólnie przypisuje wszystkie pasujące właściwości z obiektu źródłowego do celu za pomocą 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);
            }
        }
    }
 0
Author: Cogent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-15 15:06:03

Mogę ustawić właściwość klasy używając reflection, gdzie moje właściwości klasy są tylko ciągiem znaków. Teraz muszę wprowadzić jeden słownik jako członek tej klasy, ale nie mogę ustawić wartości. Używam poniższego fragmentu kodu dla właściwości string.

object objval;
objval=System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(className);
objval.GetType().GetProperty(classpropertyname).SetValue(objval,Value);

Jak ustawić wartość słownika za pomocą odbicia

 0
Author: Abhishek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 05:50:36