Access fields of a Struct in an Object with Reflection
Asked Answered
H

1

15

I'm trying to use reflection (ultimately on unknown at compile time) object which include struct. I've got as far as TypedReference.MakeTypedReference but I've hit a wall.

Here's my Class and Struct

public class MyObject
{
    public int Id;
    public Money Amount; 
}

public struct Money
{
    public int Vaule;
    public string Code;
}

And here is how I am trying to set "Code" of "Amount" in MyObject using reflection. As I mention above, I'm looking for a solution which does not know about these types at compile time (that would be too easy!)

Here's the code I have so far (I've used [0], [1] to make the code simpler)

var obj = new MyObject() { Id = 1 };
obj.Amount.Vaule = 10;
obj.Amount.Code = "ABC";

FieldInfo[] objFields = obj.GetType().GetFields();
FieldInfo[] moneyFields = objFields[1].GetValue(obj).GetType().GetFields();

List<FieldInfo> fields = new List<FieldInfo>() { objFields[1] };
fields.AddRange( moneyFields );

TypedReference typeRef = TypedReference.MakeTypedReference( 
                           objFields[1].GetValue( obj ), fields.ToArray() );

moneyFields[1].SetValueDirect( typeRef, "XXX" );

The TypedReference.MakeTypedReference blows up with; "FieldInfo does not match the target Type." Likewise if I just pass objFields[1]. And if pass just moneyFields I get "TypedReferences cannot be redefined as primitives."

Why? Let's say I'm creating Random test fixtures and want to populate class fields with random data :)

Hiroshima answered 9/11, 2012 at 12:22 Comment(7)
Are you saying that at compile time you don't know if its using MyObject or Money, so it needs to detect which object is being used and read/write the property accordingly?Scrim
How about using AutoFixture and getting out of the reflection Rube Goldberg machines business? (Though wrt struct, see #12931463) (have not run into any need for MakeTypedReference professionally and have to say something as I happened to actually be watching the tweet stream for once, sry!)Turbofan
@RubenBartelink - the "why" was simply for reference. Would defo' use AutoFixture if that was what I was doing.Hiroshima
@activwerx It's purely using reflection on unknown objects and structs. Marc's answer below is the perfect answer for this situation.Hiroshima
@IanQuigley I'm guessing I definitely wouldn't like to work on the real problem...Turbofan
@RubenBartelink the whole thing was a BAD idea, and am following the advice of Marc Gravell and many others. Poco's all the way :) I only dug into it and posted here because I wanted to know the answer academically.Hiroshima
Possible duplicate of Is there a way to set properties on struct instances using reflection?Panhandle
C
21

Frankly, there's no need whatsoever for TypedReference here - just a boxed struct should work fine:

    var amountField = obj.GetType().GetField("Amount");
    object money = amountField.GetValue(obj);
    var codeField = money.GetType().GetField("Code");
    codeField.SetValue(money, "XXX");
    amountField.SetValue(obj, money);

However! I will advise you of a few things:

  • public fields instead of properties are not usually a good idea; that will often bite you later
  • mutable structs (i.e. structs that can be changed after creation) are almost never a good idea, and will bite even more often, and bite harder
  • combining mutable structs and public fields compounds it, but making it very problematic to change later
Capacious answered 9/11, 2012 at 12:40 Comment(5)
@Ian just please note the bullet points... this is not a great ideaCapacious
@MarcGravell Can you please explain (or give a link where I can learn from) why boxing is needed for using reflection on struct. Other than boxing rest of the steps are same as a regular reflection.Cheiron
@Sнаđошƒаӽ because all the reflection APIs take object as their input.Capacious
@Marc Isn't struct an object too? Inheritance chain is Object -> ValueType -> struct right?Cheiron
@Sнаđошƒаӽ it can behave as an object, via boxing. Until then: no, it isn't an object in the "heap" sense or the OO sense.Capacious

© 2022 - 2024 — McMap. All rights reserved.