C#反射来自通用基类中的字段的GetValue

时间:2012-07-11 23:02:46

标签: c# generics reflection fieldinfo

问题在于我们不能只存在于具有泛型类型的基类中的字段(非泛型)的GetValue。 请参阅下面的代码段。调用

f.GetValue(a)

将抛出带有消息的异常:无法对Type.ContainsGenericParameters为true的类型的字段执行后期绑定操作。

class Program
{
    static void Main(string[] args)
    {
        Type abstractGenericType = typeof (ClassB<>);
        FieldInfo[] fieldInfos =
            abstractGenericType.GetFields(BindingFlags.Public |  BindingFlags.Instance);

        ClassA a = new ClassA("hello");
        foreach(FieldInfo f in fieldInfos)
        {
            f.GetValue(a);// throws InvalidOperationhException 
        }
    }
}

internal class ClassB<T>
{
    public string str;
    public ClassB(string s)
    {
        str = s;
    }
}

internal class ClassA : ClassB<String>
{
    public ClassA(string value) : base(value)
    {}
}

我们的设计要求我们在拥有实际对象的任何实例之前首先获得FieldInfo。所以我们不能使用

Type typeA = abstractGenericType.MakeGenericType(typeof(string));
FieldInfo[] fieldInfos = typeA.GetFields();

谢谢

2 个答案:

答案 0 :(得分:0)

我想这个问题来自于通用类是使用特定类型动态编译的。泛型类型也可以定义为

internal class ClassB<T>
{
    public T value;

    public string str;
    public ClassB(string s)
    {
        str = s;
    }
}

那么你在获取字段“value”的值时会遇到问题。变通办法将使用.GetType()直接检索类型,或创建一个没有包含您要访问的字段的通用参数的新基类。

答案 1 :(得分:0)

如果您灵活并且愿意使用属性而不是字段,则可以通过在通用基类上放置非泛型接口来实现您想要的功能。这是原始代码的重新分解版本,显示了变化和概念。

    class Program
    {
        public static void Main(string[] args)
        {
            Type interfaceType = typeof(IGetStr);
            PropertyInfo[] propertyInfos = interfaceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            ClassA a = new ClassA("hello");

            foreach (PropertyInfo p in propertyInfos)
            {
                var myValue = p.GetValue(a, null); // does not throw InvalidOperationException 
            }
        }
    }

    internal interface IGetStr
    {
        string StringValue { get; set; }
    }

    internal class ClassB<T> : IGetStr
    {
        public string str;

        public ClassB(string s)
        {
            str = s;
        }

        public string StringValue
        {
            get
            {
                return str;
            }
            set
            {
                str = value;
            }
        }
    }

    internal class ClassA : ClassB<String>
    {
        public ClassA(string value)
            : base(value)
        { }
    }

接口是访问泛型类的非泛型属性的好方法。使用如图所示的接口,您可以获取名为“StringValue”的属性,以获取继承自ClassB&lt;&gt;的任何类。无论泛型类型如何,只要使用IGetStr的接口。

您也可以将“ClassA”对象转换为IGetStr,以下内容将起作用。 (非常适合所有从您的通用基础继承的项目列表)

var result = ((IGetStr)a).StringValue;