C# Developing .Net3.5 using reflection to get/set values to nested properties and/or nested fields

六月ゝ 毕业季﹏ 提交于 2019-12-18 09:37:04

问题


I'm developing an app that works with data block classes inheritied from a base class and I am trying to use Reflection to drill down to properties/fields in my data block class. Since all the data block classes are derived/inherited from the base class (which contains a Size property) I can use a general variable of type base class to create an object in my app easily enough; I can also get/set properties at a top level. My problem occurs when the property is a field - I do not know how to get to the next level in the field to get to the base properties and/or fields, if applicable.

My BaseClass:

namespace MyBase {
   public class BaseClass {
       private int _size;
       public BaseClass() { }
       public BaseClass(int size) {
           _size = size;
       }
       public int Size() {
           return _size; 
       }
   }
}

Data block class #1:

namespace DataBlock_class {
    //Data block class #1: (contains simple properties - will be used later)
    public class RecordBlock1_class : MyBase.BaseClass {
        public byte Char { get; set; }
        public byte Color { get; set; }
        public RecordBlock1_class() : base(2) {
            Char = 0;
            Color = 0;
        }
    }

    //Data block class #2: (contains simple properties)
    public RecordBlock2_class : MyBase.BaseClass {
        public bool Boolean1 { get; set; }
        public byte Byte1 { get; set; }
        public short Short1 { get; set; }
        public ushort UShort1 { get; set; }
        public RecordBlock2_class() : base(11) {
            Boolean1 = false;
            Byte1 = 0;
            Short1 = 0;
            UShort1 = 0;
        }
    }
    //Data block class #3: (contains simple properties & fields)
    public RecordBlock3_class : MyBase.BaseClass {
        public int Int1 { get; set; }
        public uint UInt1 { get; set; }
        public RecordBlock1_class[] ArrayField1 { get; set; }  // array of 12
        public RecordBlock1_class[] ArrayField2 { get; set; }  // array of 12
        public RecordBlock1_class[] ArrayField3 { get; set; }  // array of 12
        public RecordBlock2_class() : base(34) {
            Int1 = 0;
            UInt1 = 0;
            ArrayField1 = new RecordBlock1_class[12];
            for(int x = 0; x < 12; x++) {
                ArrayField1[x] = new RecordBlock1_class();
            }
            ArrayField2 = new RecordBlock1_class[12];
            for(int x = 0; x < 12; x++) {
                ArrayField2[x] = new RecordBlock1_class();
            }
            ArrayField3 = new RecordBlock1_class[12];
            for(int x = 0; x < 12; x++) {
                ArrayField3[x] = new RecordBlock1_class();
            }
        }
    }
}

Since all my data block classes derive/inherit from MyBase.BaseClass, I can use this for my variable - I do not what type of data block class I will be processing at run time.

in my C# app, I have the following block of code:

string CSharpQualifiedName = "<this could be any of the data block classes above>";
// DataBlock_class.RecordBlock1_class
// DataBlock_class.RecordBlock2_class
// DataBlock_class.RecordBlock3_class

Using my MyBase.BaseClass variable, I can then instantiate a MyBase.BaseClass object:

MyBase.BaseClass baseClass = null;
Type baseClassType = Type.GetType(CSharpQualifiedName);
if(baseClassType == null) {
    foreach(Assembly asm in AppDomain.CurrentDomain.GetAsseblies()) {
        baseClassType= asm.GetType(CSharpQualifiedName);
        if(baseClassType != null) {
            baseClass = Activator.CreateInstance(baseClassType) as MyBase.BaseClass;
            break;
        }
    }
}

Dealing with the first two data block classes are easy enough - I can using PropertyInfo to get/set values.

string fieldProperty = "<any property in the class>";
PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);

Now, my proplem/issue is RecordBlock3_class - How do I get to one of the items in any of array fields/properties AND then to the Char/Color property in RecordBlock1_class???

I can use FieldInto to get to the ArrayFieldX fields, but I'm lost after that?

FieldInfo fi = baseClass.GetType().GetField(fieldProperty);

Any assistance/advice is greatly appreicated!! I will say one more thing, the data block classes can get a bit more complex as users create more nested class structures.


回答1:


You can get element type of the array property by Reflection also, and then get its properties normally:

string fieldProperty = "ArrayField1";
System.Reflection.PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);
if (pi.PropertyType.IsArray)
{
    Type elementType = pi.PropertyType.GetElementType();
    System.Reflection.PropertyInfo pi2 = elementType.GetProperty("Color");
}

Based on that, you can write simple yet more generic function that is traversing nested properties (to use also fields, simply modify below code):

static System.Reflection.PropertyInfo GetProperty(Type type, string propertyPath)
{
    System.Reflection.PropertyInfo result = null;
    string[] pathSteps = propertyPath.Split('/');
    Type currentType = type;
    for (int i = 0; i < pathSteps.Length; ++i)
    {
        string currentPathStep = pathSteps[i];
        result = currentType.GetProperty(currentPathStep);
        if (result.PropertyType.IsArray)
        {
            currentType = result.PropertyType.GetElementType();
        }
        else
        {
            currentType = result.PropertyType;
        }
    }
    return result;
}

and then you can 'query' objects with 'paths':

PropertyInfo pi = GetProperty(c1.GetType(), "ArrayField1/Char");
PropertyInfo pi2 = GetProperty(c2.GetType(), "Color");

If you want to get values of object in this way, a method will be similar:

static object GetPropertyValue(object obj, string propertyPath)
{
    System.Reflection.PropertyInfo result = null;
    string[] pathSteps = propertyPath.Split('/');
    object currentObj = obj;
    for (int i = 0; i < pathSteps.Length; ++i)
    {
        Type currentType = currentObj.GetType();
        string currentPathStep = pathSteps[i];
        var currentPathStepMatches = Regex.Match(currentPathStep, @"(\w+)(?:\[(\d+)\])?");
        result = currentType.GetProperty(currentPathStepMatches.Groups[1].Value);
        if (result.PropertyType.IsArray)
        {
            int index = int.Parse(currentPathStepMatches.Groups[2].Value);
            currentObj = (result.GetValue(currentObj) as Array).GetValue(index);
        }
        else
        {
            currentObj = result.GetValue(currentObj);
        }

    }
    return currentObj;
}

And then you can get values queries, including arrays, for example:

var v = GetPropertyValue(baseClass, "ArrayField1[5]/Char");

Of course both methods requires some polishing of error handling etc.



来源:https://stackoverflow.com/questions/19936888/c-sharp-developing-net3-5-using-reflection-to-get-set-values-to-nested-properti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!