13

I have a generic Type as follows

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

If i have now an object (which is coming from some external source) from which i know that it's type is of some closed TestGeneric<>, but i don't know the TypeParameter T. Now I need to access the Data of my object. Problem is that i can't cast the object, since i don't know exactly to which closed TestGeneric.

I use

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

to make sure, my object is of the generic type. The code in question is as follows:

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[] { });
    }
}

I need the Data regardless of its type (well, if i could ask for its type using GetType() would be fine, but not necessary) since i just want to dump it in xml using ToString().

Any suggestions? Thanx.

Martin Booka Weser
  • 3,192
  • 5
  • 28
  • 41
  • possible duplicate of [Accessing properties through Generic type parameter](http://stackoverflow.com/questions/3059420/accessing-properties-through-generic-type-parameter) – Chris Moschini Nov 03 '13 at 20:04

4 Answers4

31

Oh, stackies... why didn't somebody point me to the dynamic type?? That's the perfect usage example which makes the code A LOT more readable:

dynamic dynObject = myObject;
object data = dynObject.Data;
Martin Booka Weser
  • 3,192
  • 5
  • 28
  • 41
  • 1
    Official MSDN docs on usage https://msdn.microsoft.com/en-us/library/Dd264736.aspx This really feels like the appropriate answer. Can someone mark it as correct please? – Ash Blue Sep 10 '15 at 16:11
12

You need to know the closed type of a generic class before you can access its generic members. The use of TestGeneric<> gives you the open type definition, which cannot be invoked without specifying the generic arguments.

The simplest way for you to get the value of the property is to reflect on the closed type in use directly:

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[] { });
    }
}
Paul Turner
  • 38,949
  • 15
  • 102
  • 166
4

Ahh, sorry for that. It was a simple mistake, the generic version works, of course it must read

var dataProperty = myObject.GetType().GetProperty("Data");
object data = dataProperty.GetValue(myObject, new object[] { });
Martin Booka Weser
  • 3,192
  • 5
  • 28
  • 41
1

With C# 6 and up we can use nameof to improve slightly Paul's answer:

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

Notice that replacing type.GetProperty("Data") with type.GetProperty(nameof(TestGeneric<object>.Data)) gives you compile time safety (so arguably better than using the dynamic way as well).

Also using object as a type parameter is just a way to get access to the property and doesn't have any side effect or particular meaning.

cheesemacfly
  • 11,622
  • 11
  • 53
  • 72