.NET Reflection set private property
Asked Answered
I

6

22

If you have a property defined like this:

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

How do you set it to a certain value with Reflection?

I've tried both:

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

and

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

but without any success. Sorry if this is a stupid question but it's the first time I'm using Reflection with C#.NET.

Incorrigible answered 22/11, 2009 at 10:51 Comment(0)
T
41

That has no setter; you'd need:

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

(you might have to use BindingFlags - I'll try in a moment)

Without a setter, you'd have to rely on patterns / field names (which is brittle), or parse the IL (very hard).

The following works fine:

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

It also works with an auto-implemented property:

public DateTime ModifiedOn { get; private set; }

(where relying on the field-name would break horribly)

Taluk answered 22/11, 2009 at 10:52 Comment(6)
Cool, hadn't thought about being able to have private in front of the setter. And I'll have to check those BindingFlags I guess. Thx.Incorrigible
It looks like you only need BindingFlags if the entire property is private.Taluk
Still doesn't work so I guess I'll have to use those BindingFlags?Incorrigible
Define "doesn't work" - what happens? The example I posted works fine... also: are you using CF? Silverlight? or regular .NET? (it matters...)Taluk
One moment, may have forgotten something.Incorrigible
Since the getter is public, you should definitely replace "ModifiedOn" by nameof(Test.ModifiedOn). This way a property rename won't cause runtime exceptions.Zobe
C
4

You could try to set the backing field and not the property; you should use GetField() not GetProperty().

Circle answered 22/11, 2009 at 10:57 Comment(3)
While that would work, accessing fields is generally an even-more brittle form of reflection. For example, what happens when somebody discovers C# 3.0 and makes it: public DateTime ModifiedOn { get; private set; } ?Taluk
If you do want to set the backing field, to minimize chance of breaking, I would attempt to find each of the following three possibilities: (1) Same name, igoring case. (2) Underscore + same name, ignoring case. (3) Default naming scheme for backing fields of auto-properties (easily found on SO).Zobe
Note that GetField() has an overload that allows IgnoreCase.Zobe
R
3

If your property doesn't have a setter, you can't call SetValue on it.

Rheumatic answered 22/11, 2009 at 10:53 Comment(0)
G
1

You need to set the field because you have no set property to set the property. Additional the BindingFlags.NonPublic is needed for not public objects.

dto.GetType().
    GetField("modifiedOn", 
    BindingFlags.NonPublic|BindingFlags.SetField|BindingFlags.Instance).
    SetValue(dto, valueToSet);
Grady answered 24/11, 2016 at 13:42 Comment(0)
F
0

If you have a private property with a setter then you can use this Extension method to set a value:

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);
    }
}
Fullfaced answered 30/10, 2017 at 22:5 Comment(0)
N
0

One way to do it, and this is might be the most correct way, considering that set may or may not exist, is to use a specific accessor

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);
}
News answered 16/4, 2021 at 18:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.