59

I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:

System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);

The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.

I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.

2 Answers 2

96

The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:

Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Sign up to request clarification or add additional context in comments.

8 Comments

Incidentally, this is a good example of one of the perils of mutable value types.
Just make sure that you're not doing this in a loop (or that performance isn't an issue), especially if the structure is large. :-)
+1 I had exactly the same issue. @Dan Bryant - while I agree that mutable structs are evil, the reason I am doing this is to make a factory class for immutable structs and I need to be able to set readonly properties. I'm doing something sort of similar to what the MVC Model Binder subsystem does, although much simpler and nothing to do with the web. So I'm making immutable structs, but I'm allowing myself to mutate them once only, at the point of creation, so I think that will avoid all the potential evil.
Who's using VB.net should instead use the following example: Dim _rectangle As New Rectangle() Dim _propertyInfo As PropertyInfo = GetType(Rectangle).GetProperty("Height") Dim boxed As ValueType = _rectangle _propertyInfo.SetValue(boxed, 5, Nothing) _rectangle = DirectCast(boxed, Rectangle)
@Sнаđошƒаӽ: No, a value type value isn't an object, despite the inheritance hierarchy. Boxing is precisely the process of allocating an object to hold a value type value, and then getting a reference to that object. There isn't space here to go into the difference between value types and reference types, but I strongly urge you to research them.
|
20

Ever heard of SetValueDirect? There's a reason they made it. :)

struct MyStruct { public int Field; }

static class Program
{
    static void Main()
    {
        var s = new MyStruct();
        s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
        System.Console.WriteLine(s.Field); //Prints 5
    }
}

There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.

5 Comments

Note that "This API is not CLS-compliant.".
__makeref() not implement in Unity3d with IL2CPP
Unfortunately, apart from not being CLS-compliant, SetValueDirect and TypedReference simply do not work with readonly fields in structs. SetValue does work in those conditions.
@EduardDumitru I'm not sure whether or not SetValueDirect's implementation has changed ever since you wrote your comment; however, I've just used it to modify a public readonly field on a struct, and it worked.
What if the issue you are using Reflection to get the original object e.g. you can't call __makeref on GetValue...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.