1

我正在开发一个与从基类继承的数据块类一起使用的应用程序,并且我正在尝试使用反射来深入了解我的数据块类中的属性/字段。由于所有数据块类都是从基类(包含 Size 属性)派生/继承的,因此我可以使用基类类型的通用变量在我的应用程序中轻松创建对象;我还可以在顶层获取/设置属性。当属性是一个字段时会出现我的问题 - 我不知道如何进入该字段的下一个级别以获取基本属性和/或字段(如果适用)。

我的基类:

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

数据块类#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();
            }
        }
    }
}

由于我所有的数据块类都从 MyBase.BaseClass 派生/继承,因此我可以将它用于我的变量 - 我不知道我将在运行时处理哪种类型的数据块类。

在我的 C# 应用程序中,我有以下代码块:

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

使用我的 MyBase.BaseClass 变量,我可以实例化一个 MyBase.BaseClass 对象:

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;
        }
    }
}

处理前两个数据块类很容易——我可以使用 PropertyInfo 来获取/设置值。

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

现在,我的问题/问题是 RecordBlock3_class - 如何获取任何数组字段/属性中的项目之一,然后到 RecordBlock1_class 中的 Char/Color 属性?

我可以使用 FieldInto 来访问 ArrayFieldX 字段,但之后我就迷路了?

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

非常感谢任何帮助/建议!我还要说一件事,随着用户创建更多嵌套的类结构,数据块类可能会变得更复杂一些。

4

1 回答 1

2

您也可以通过反射获取数组属性的元素类型,然后正常获取其属性:

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");
}

基于此,您可以编写简单但更通用的函数来遍历嵌套属性(也可以使用字段,只需修改以下代码):

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;
}

然后您可以使用“路径”“查询”对象:

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

如果您想以这种方式获取对象的值,方法将类似:

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;
}

然后您可以获取值查询,包括数组,例如:

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

当然,这两种方法都需要对错误处理等进行一些改进。

于 2013-11-12T20:05:04.837 回答