如何在不知道封闭泛型类型的情况下访问通用属性

时间:2011-01-04 10:35:26

标签: c# reflection casting generics

我有一个通用类型如下

public class TestGeneric<T>
{
    public T Data { get; set; }
    public TestGeneric(T data)
    {
        this.Data = data;
    }
}

如果我现在有一个对象(来自某个外部源),我知道它的类型是一些封闭的TestGeneric&lt;&gt;,但我不知道TypeParameter T.现在我需要访问我的对象的数据。问题是我无法强制转换对象,因为我不确切知道哪个封闭的TestGeneric。

我用

// thx to http://stackoverflow.com/questions/457676/c-reflection-check-if-a-class-is-derived-from-a-generic-class
private static bool IsSubclassOfRawGeneric(Type rawGeneric, Type subclass)
{
    while (subclass != typeof(object))
    {
        var cur = subclass.IsGenericType ? subclass.GetGenericTypeDefinition() : subclass;
        if (rawGeneric == cur)
        {
            return true;
        }
        subclass = subclass.BaseType;
    }
    return false;
}

要确保,我的对象属于泛型类型。有问题的代码如下:

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source
    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), myObject.GetType()))
    {
        // the following gives an InvalidCastException
        // var data = ((TestGeneric<object>)myObject).Data;

        // if i try to access the property with reflection
        // i get an InvalidOperationException
        var dataProperty = typeof(TestGeneric<>).GetProperty("Data");
        object data = dataProperty.GetValue(myObject, new object[] { });
    }
}

我需要Data而不管它的类型(好吧,如果我可以使用GetType()来询问它的类型会很好,但不是必需的)因为我只想使用ToString()将其转储到xml中。

有什么建议吗?感谢名单。

4 个答案:

答案 0 :(得分:28)

哦,堆叠......为什么没有人指我dynamic类?这是一个完美的用法示例,它使代码更具可读性:

dynamic dynObject = myObject;
object data = dynObject.Data;

答案 1 :(得分:12)

在访问其通用成员之前,您需要知道泛型类的封闭类型。 TestGeneric<>的使用为您提供了开放类型定义,如果不指定泛型参数,则无法调用该定义。

获取属性值的最简单方法是直接反映使用中的封闭类型:

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source

    var type = myObject.GetType();

    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), type))
    {
        var dataProperty = type.GetProperty("Data");
        object data = dataProperty.GetValue(myObject, new object[] { });
    }
}

答案 2 :(得分:4)

对不起,对不起。这是一个简单的错误,通用版本有效,当然必须阅读

var dataProperty = myObject.GetType().GetProperty("Data");
object data = dataProperty.GetValue(myObject, new object[] { });

答案 3 :(得分:1)

在C#6及更高版本中,我们可以使用nameof来稍微改善Paul的答案:

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source

    var type = myObject.GetType();

    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), type))
    {
        var dataProperty = type.GetProperty(nameof(TestGeneric<object>.Data));
        object data = dataProperty.GetValue(myObject);
    }
}

请注意,将type.GetProperty("Data")替换为type.GetProperty(nameof(TestGeneric<object>.Data))可以提高编译时的安全性(因此比使用dynamic更好。)

还将object用作类型参数只是访问该属性的一种方式,并且没有任何副作用或特殊含义。