19

I have seen various questions raised and answered where we can invoke a private setter using reflection such as this one:

Is it possible to get a property's private setter through reflection?

However I have some code which has a property i need to set but cant because there is no setter, I cant add a setter as this isn't my code. Is there a way to somehow set the value using reflection in this scenario?

Community
  • 1
  • 1
Luke De Feo
  • 1,906
  • 3
  • 21
  • 38
  • 5
    Properties have no values. They may have setters which may alter the value of another field. If you're interested in finding the backing field of an auto-generated property, see this question: http://stackoverflow.com/questions/8817070/is-it-possible-to-access-backing-fields-behind-auto-implemented-properties – Rotem Dec 18 '13 at 18:14

3 Answers3

30

I do not suggest doing this on your application but for testing purpose it may be usefull...

Assuming you have:

public class MyClass
{
     public int MyNumber {get;}
}

You could do this if its for test purpose, I would not suggest to use this in your runtime code:

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(anIstanceOfMyClass, 3);
Abyte0
  • 782
  • 7
  • 9
  • Thank you. I was trying to change value of a getter only property and there was absolutely no way I can add a setter for that property - this helped. – Mosharaf Hossain Jan 18 '18 at 15:04
  • 2
    That is my idea as well for this. The answer should say: "**Try to find a field that holds the actual data you want to change.**" – Bitterblue Jul 02 '18 at 08:54
  • this is still working at this time, this answer the right one for me ;) – Vielinko Nov 26 '20 at 18:41
7

You have to keep in mind that a property is just syntactic sugar for a pair of methods. One method (the getter) returns a value of the property type and one method (the setter) accepts a value of the property type.

There is no requirement that the getter and setter actually get or set anything. They're just methods, so they're allowed to do anything. The only requirement is that the getter return a value. From the outside there's no way you can really tell if there is a backing field. The getter could be getting computed every time it's called. It may be based on other properties.

So, no, there isn't really any way in general to "set" a property that doesn't have a setter.

Kyle
  • 6,250
  • 2
  • 30
  • 39
  • 1
    This is wrong. Using reflection, you can set the backing field. The problem is knowing what the backing field is. – Austin Salgat Sep 15 '18 at 19:39
  • 4
    @Salgat The point is that properties don't need to have backing fields, so you can't "know the backing field" in general, because it may not exist. For example, `public int Property { get { return 5; } }` is perfectly valid and does not have a backing field. Furthermore it's possible a property could depend on multiple backing fields, further muddying what it means to be able to "set" it. E.g. `public double Length { get { return Math.Sqrt(this.x * this.x + this.y * this.y); } }`. – Kyle Sep 15 '18 at 20:10
  • That's the whole point of reflection though. You can use something like the type.GetField method to determine if the backing field even exists (returning null if it doesn't). The OP clearly states, can you use reflection to set the value, which is usually possible. – Austin Salgat Sep 15 '18 at 20:18
  • 3
    @Salgat Kyle's answer clearly states that there is no *general* way of doing this and he is correct. – deloreyk Sep 15 '18 at 20:22
  • There is a general way of doing this that comes with an exception (when the property is not auto-implemented). But at this point, we're arguing semantics. – Austin Salgat Sep 16 '18 at 18:55
  • Downvoting. This is factually incorrect and should be updated or removed. – Dan Solovay Mar 20 '21 at 17:28
0

Adding a practical use case to @abyte0's answer.

Some libraries make use of reflection to set properties this way. For example, see this sample code from https://github.com/natemcmaster/CommandLineUtils:

using System;
using McMaster.Extensions.CommandLineUtils;

public class Program
{
    public static int Main(string[] args)
        => CommandLineApplication.Execute<Program>(args);

    [Option(Description = "The subject")]
    public string Subject { get; } = "world";

    [Option(ShortName = "n")]
    public int Count { get; } = 1;

    private void OnExecute()
    {
        for (var i = 0; i < Count; i++)
        {
            Console.WriteLine($"Hello {Subject}!");
        }
    }
}

Behind the scenes, this syntax is implemented with this code:

        public static SetPropertyDelegate GetPropertySetter(PropertyInfo prop)
        {
            var setter = prop.GetSetMethod(nonPublic: true);
            if (setter != null)
            {
                return (obj, value) => setter.Invoke(obj, new object?[] { value });
            }
            else
            {
                var backingField = prop.DeclaringType.GetField($"<{prop.Name}>k__BackingField", DeclaredOnlyLookup);
                if (backingField == null)
                {
                    throw new InvalidOperationException(
                        $"Could not find a way to set {prop.DeclaringType.FullName}.{prop.Name}. Try adding a private setter.");
                }

                return (obj, value) => backingField.SetValue(obj, value);
            }
        }

The practical value here is having the code express that the only way a value should be set is through a command line invocation. This is allowed: hello.exe -s world but this is not: Subject = "some other value";

Dan Solovay
  • 3,071
  • 3
  • 23
  • 53