.NET Reflection установить частную собственность

Если у вас есть свойство, определенное следующим образом:

private DateTime modifiedOn;
public DateTime ModifiedOn
{
    get { return modifiedOn; }
}

Как вы установите его на определенное значение с отражением?

Я пробовал оба:

dto.GetType().GetProperty("ModifiedOn").SetValue(dto, modifiedOn, null);

а также

dto.GetType().GetProperty("modifiedOn").SetValue(dto, modifiedOn, null);

но безуспешно Извините, если это глупый вопрос, но я впервые использую Reflection с C#.NET.

6 ответов

Решение

У этого нет сеттера; вам нужно:

public DateTime ModifiedOn
{
    get { return modifiedOn; }
    private set {modifiedOn = value;}
}

(возможно, вам придется использовать BindingFlags - попробую через минуту)

Без установщика вам придется полагаться на шаблоны / имена полей (что является хрупким) или анализировать IL (очень сложно).

Следующее работает отлично:

using System;
class Test {
    private DateTime modifiedOn;
    public DateTime ModifiedOn {     
        get { return modifiedOn; }
        private set { modifiedOn = value; }
    }
}
static class Program {
    static void Main() {
        Test p = new Test();
        typeof(Test).GetProperty("ModifiedOn").SetValue(
            p, DateTime.Today, null);
        Console.WriteLine(p.ModifiedOn);
    }
}

Он также работает с автоматически реализованным свойством:

public DateTime ModifiedOn { get; private set; }

(где опора на имя поля ужасно сломается)

Вы можете попытаться установить поле поддержки, а не свойство; ты должен использовать GetField() не GetProperty(),

Если в вашем свойстве нет сеттера, вы не можете вызвать SetValue.

Вам необходимо установить поле, потому что у вас нет установленного свойства для установки свойства. Дополнительно необходим BindingFlags.NonPublic для непубличных объектов.

dto.GetType().
    GetField("modifiedOn", 
    BindingFlags.NonPublic|BindingFlags.SetField|BindingFlags.Instance).
    SetValue(dto, valueToSet);

Если у вас есть частное свойство с установщиком, вы можете использовать этот метод Extension для установки значения:

using System.Reflection;

public static class ObjectExtensions
{
    public static void SetPrivateValue<T>(this T obj, string propertyName, object value)
    {
        var type = typeof(T);
        type.GetTypeInfo().GetDeclaredProperty(propertyName).SetValue(obj, value, null);
    }
}

Один из способов сделать это, и это, возможно, самый правильный способ, учитывая, что set может или не может существовать, заключается в использовании определенного аксессуара

      var myc = new MyClass();
var pi = typeof(MyClass).GetProperty("Prop1", BindingFlags.NonPublic | BindingFlags.Instance);

if (pi.SetMethod != null) // check if you have 'set' accessor
    pi.SetMethod.Invoke(myc, new object[]{ someValue });
else
{
    // do nothing OR
    throw new Exception("Attempted to set read-only property " + pi.Name);
}
Другие вопросы по тегам