C# - Set Property of a Property with Reflection

2019-06-08 03:24发布

问题:

SO Community,

So I'm learning C# and am still trying to wrap my head around reflection. In particular trying to use it to access a property of a property on a class.

I've boiled down the basic task that I'm trying to accomplish below:

public enum SIGNAL_STATE { NOT_RETRIEVED = 0, RETRIEVING = 1, RETRIEVED = 2, FAILED = 3 }

public class MyObjectClass
{
    public string MyString;
    private SIGNAL_STATE _state = SIGNAL_STATE.NOT_RETRIEVED;
    public SIGNAL_STATE State { get { return _state; } set { _state = value;} }
}

public class NeedToReflect
{
    private MyObjectClass _myObject1 = new MyObjectClass();
    private MyObjectClass _myObject2 = new MyObjectClass();
    private MyObjectClass _myObject3 = new MyObjectClass();

    public MyObjectClass MyObject1
    {
        get{return _myObject1;} 
        set{_myObject1 = value;}
    }

    public MyObjectClass MyObject2
    {
        get{return _myObject2;}
        set{_myObject2 = value;}
    }

    public MyObjectClass MyObject3
    {
        get{return _myObject3;}
        set{_myObject3 = value;}
    }

    public static void Main(string [] args){
        NeedToReflect needToReflect = new NeedToReflect();

        string fieldName;
        for(int idx = 1; idx<=3; ++idx)
        {
            fieldName = String.Format("MyObject{0}",idx);

            //TODO: set state of 'MyObject' values to SIGNAL_STATE.RETRIEVING

        }
    }
}

edit 1:

At Yair Nevet's suggestion I'm grabbing the FieldInfo from the applicable object like,

FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);

But from there I get hung up on accessing and setting the right 'State' Field/Property on that member field

Solution (ie. here's what I plugged in on that TODO comment):

// Determine what binding flags will give us proper access to our member field
BindingFlags bindFlags = BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance;
// Get the field for that field
FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, bindFlags);
// Pass in the containing object that we're reflecting on to get an instance of the member field
MyObjectClass myField = (MyObjectClass) fieldInfo.GetValue(needToReflect);
// We can now directly access and edit the value in question
myField.State = SIGNAL_STATE.RETRIEVING;

That does it. Thanks to Shlomi Borovitz for pointing me in the right direction.

Thanks!

回答1:

The FieldInfo object which returned by GetField has property which called FieldInfo, which returns the type of that field. And you can query it for that type's (the type of the field) properties/fields (and whatever you want) - and get/set them.

Remember that both GetType method (of any object), and the FieldInfo.FieldType property return Type object, that you can query in reflection.

object obj =... 
var field = obj.GetType().GetField(fieldName,...);
field.FieldType.GetField(... 
//etc... etc... 

For each field, you can query the type and for each type, you can query the fields, and get/set them.

BTW, in C# 4.0 you can use the dynamic pseudo type (it used as a type when declaring dynamic variable, but it's not a real type), and then using that variable, while assuming which properties/fields/methods that variable would have in runtime (ie, using them like they are known in compile time although they don't). This will not work for private members (and I can't warn you enough against calling private members in reflection), but for public members, this would make your code simple and readable, like you never used reflection (although, behind the scenes [in this case] reflection would be used).



回答2:

You are trying to access a Property while the member is actually a private Field:

propertyName = String.Format("MyObject{0}",idx);

Use GetField method instead for that:

needToReflect.GetType().GetField(propertyName, BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance);


回答3:

Go through these steps...

1) Get the Type.
2) Have an instance of that type.
3) Get the PropertyInfo for the property.
4) Call "GetSetMethod" on the PropertyInfo object. It will return a MethodInfo object.
5) Invoke the MethodInfo object using the instance of the type and a value.



标签: c# reflection