System.Reflection - 如何调用子级类型的getter方法?

4

我有三个类:

public class TestA
{
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public TestB TestB { get; set; }

    public TestA()
    {
        Str1 = "string1";
        Str2 = "string2";
        TestB = new TestB();
    }
}

public class TestB
{
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public TestC ObjTestC { get; set; }
    public TestB()
    {
        Str3 = "string3";
        Str4 = "string4";
        ObjTestC = new TestC();
    }
}

public class TestC
{
    public string Str5 { get; set; }
    public TestC()
    {
        Str5 = "string5";
    }
}

现在,我已经获得了所有的PropertyInfo并创建了一个新对象:
        //Get all the properties

        var prop = typeof(TestA).GetProperties();

        for (int i = 0; i < prop.Count(); i++)
        {
            var propertyInfo = prop[i];
            if (propertyInfo.PropertyType.Namespace != "System")
            {
                if (propertyInfo.PropertyType.IsGenericType &&
                    propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                {
                    Type itemType = propertyInfo.PropertyType.GetGenericArguments()[0]; // use this...
                    var listObjectProperties = itemType.GetProperties();
                    prop = prop.Union(listObjectProperties).ToArray();
                }
                else
                {
                    var childProp = propertyInfo.PropertyType.GetProperties();
                    prop = prop.Union(childProp).ToArray();
                }
            }
        }


        //Create Object
        TestA testA = new TestA();

现在,我的需求是调用每个属性的getter方法。我尝试了以下代码,它调用了TestA类的属性getter,但是当尝试调用TestB和TestC的属性getter时,它会抛出错误:

        // Loop through all properties
        foreach (PropertyInfo propertyInfo in prop)
        {
            MethodInfo getterMethodInfo = propertyInfo.GetGetMethod();
            var obj=getterMethodInfo.Invoke(testA, null);
        }

帮我一个忙...

提前感谢您


你具体遇到了什么错误? - Philip Kendall
对象与目标类型不匹配。 - SKB
2
它并不是这样的。你似乎认为TestB和TestC继承了TestA类。但事实并非如此,因为你没有以这种方式编写它们。 - Hans Passant
1个回答

7

检查这段代码,我期望prop数组包含TestATestB的所有属性,并且完全不影响TestC

// Gets TestA's properties...
var prop = typeof(TestA).GetProperties();

// Then gets TestB's properties...
var childProp = propertyInfo.PropertyType.GetProperties();
prop = prop.Union(childProp).ToArray();

如果您想要从所有三种类型中获取属性,那么您应该以递归的方式来实现。这样您就不必每次更改这些对象的结构时都需要修改此循环。
但这并不是真正的问题。
真正的问题是getterMethodInfo.Invoke(testA, null)针对TestB的属性被调用,但却传递了一个TestA的实例,因此出现了错误。 如果您不使用反射,您会如何获取此值? 您现有的代码基本上正在执行以下操作:
var value = testA.Str3; // !!! there is no Str3 property on TestA !!!

为了正确工作,您需要这样做:
var value = testA.TestB.Str3;

看看我们是如何通过多层属性调用来获取期望的值的?首先是TestA.TestB,然后是TestB.Str3。如果需要使用反射来实现,代码也需要做同样的事情:

var obj = (object)testA;
obj = testBPropOnTestA.GetValue(obj, null);
var value = str3PropOnTestB.GetValue(obj, null);

因此,您需要在集合中存储PropertyInfo的列表,而不是简单的实例。

因此,您最终的“获取值”循环看起来更像:

foreach (var propertyChain in prop)
{
    var obj = (object)testA;
    foreach (var property in propertyChain)
    {
        obj = property.GetValue(obj, null);
        if (obj == null) {
            break;
        }
    }
    Console.WriteLine("{0} = {1}",
        string.Join(".", propertyChain.Select(x => x.Name)),
        obj);
}

我将把如何修复第一个“收集PropertyInfo”循环的任务留给你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接