57

I have a generic class, and an object value where obj.GetType().GetGenericTypeDefinition() == typeof(Foo<>).

class Foo<T>
{
    public List<T> Items { get; set; }
}

How do I get the value of Items from obj? Remember, obj is an Object, I can't cast obj as Foo because I don't know what T is.

I was hoping to use reflection for this, but each time I do GetProperty("Items") it returns null. However, if someone knows a good way to do this without reflection, by all means.

Let's say my code looks like this:

//just to demonstrate where this comes from
Foo<int> fooObject = new Foo<int>();
fooObject.Items = someList;
object obj = (object)fooObject;

//now trying to get the Item value back from obj
//assume I have no idea what <T> is
PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
object itemValue = propInfo.GetValue(obj, null); //and this breaks because it's null
gunr2171
  • 16,104
  • 25
  • 61
  • 88
  • 2
    Are you calling GetProperty() on typeof(Foo<>)? – luksan Jan 02 '13 at 21:27
  • 1
    `GetProperty` should be fine. Please post a short but complete program demonstrating the problem. `dynamic` would work well too, if you're using .NET 4. – Jon Skeet Jan 02 '13 at 21:28
  • @JonSkeet sorry, I'm using 3.5. Example code above. – gunr2171 Jan 02 '13 at 21:35
  • Using your (nearly) exact [code with .Net 3.5 and MS VC# 2k8 works just fine](http://i.stack.imgur.com/ko4wh.png). – user7116 Jan 02 '13 at 21:37
  • @gunr2171: Your example doesn't compile, and after applying the obvious fixes, `GetProperty` *doesn't* return null. Please show a short but complete program which *does* actually demonstrate the problem. – Jon Skeet Jan 02 '13 at 21:37
  • related: http://stackoverflow.com/questions/4592644/how-to-access-generic-property-without-knowing-the-closed-generic-type – nawfal Apr 18 '13 at 10:46

5 Answers5

98

You should be able to use:

Type t = obj.GetType();

PropertyInfo prop = t.GetProperty("Items");

object list = prop.GetValue(obj);

You will not be able to cast as a List<T> directly, of course, as you don't know the type T, but you should still be able to get the value of Items.


Edit:

The following is a complete example, to demonstrate this working:

// Define other methods and classes here
class Foo<T>
{
    public List<T> Items { get; set; }
}

class Program
{
    void Main()
    {   
        //just to demonstrate where this comes from
        Foo<int> fooObject = new Foo<int>();
        fooObject.Items = new List<int> { 1, 2, 3};
        object obj = (object)fooObject;

        //now trying to get the Item value back from obj
        //assume I have no idea what <T> is
        PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
        object itemValue = propInfo.GetValue(obj, null);

        Console.WriteLine(itemValue);
                    // Does not print out NULL - prints out System.Collections.Generic.List`1[System.Int32]


        IList values = (IList)itemValue;
        foreach(var val in values)
            Console.WriteLine(val); // Writes out values appropriately
    }
}
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
18

@ReedCopsey is absolutely correct, but in case you're really asking the question "How do I fish out the generic details of a type?", here's some "Fun with Reflection":

public void WhatsaFoo(object obj)
{
    var genericType = obj.GetType().GetGenericTypeDefinition();
    if(genericType == typeof(Foo<>))
    {
        // Figure out what generic args were used to make this thing
        var genArgs = obj.GetType().GetGenericArguments();

        // fetch the actual typed variant of Foo
        var typedVariant = genericType.MakeGenericType(genArgs);

        // alternatively, we can say what the type of T is...
        var typeofT = obj.GetType().GetGenericArguments().First();

        // or fetch the list...
        var itemsOf = typedVariant.GetProperty("Items").GetValue(obj, null);
    }
}
JerKimball
  • 16,584
  • 3
  • 43
  • 55
  • So I'm not sure if it's your code or not, but this is the first one that made it work. (not sure why you have -1 here, it's fine by my standards) – gunr2171 Jan 02 '13 at 21:52
  • 4
    @gunr2171 Eh, probably because I wasn't trying to actually answer the stated question...*shrug* I care not for downvotes, I do like talking about neat code, however. :) – JerKimball Jan 02 '13 at 21:56
  • @sixlettervariables point taken, although arguably my answer, albeit not 100% directed at the original question, does answer the inferred questions of how to reflect upon the generic arguments of a type. My "neat code" comment is rather flippant, I admit. – JerKimball Jan 02 '13 at 23:16
  • @JerKimball: your code is much more complex than necessary, a simple `obj.GetType().GetProperty("Items")` will suffice, even if it is a generic type. – user7116 Jan 03 '13 at 04:30
  • 1
    @sixlettervariables Again, not disagreeing, but in the original question: "I can't cast obj as Foo because I don't know what T is." and "assume I have no idea what is" -> implies to me that he was asking how to determine the typed variant of a generic class if you had the untyped (well, unbound generic) version.....Of course, now I'm just being pedantic; I fully admit the code I've got here is totally unnecessary given the various updates. – JerKimball Jan 03 '13 at 04:46
  • 1
    @JerKimball you code helped me in solving another problem, thank you! – Rajiv May 21 '14 at 18:29
5

Something like this should do the trick:

var foo = new Foo<int>();
foo.Items = new List<int>(new int[]{1,2,3});

// this check is probably not needed, but safety first :)
if (foo.GetType().GetProperties().Any(p => p.Name == "Items"))
{
    var items = foo.GetType().GetProperty("Items").GetValue(foo, null);
}
sa_ddam213
  • 42,848
  • 7
  • 101
  • 110
2

You have to use System.Reflection namespace to execute the program successfully.

This program gives you Property Name and Value of any Generic Class

You can check this code fiddle on C# Online Rexter Tool Compiler at

using System;
using System.Reflection;

namespace GenericPropertyExample
{
    //Declaring a Sample Class 
    public class class1
    {
        public string prop1 { get; set; }
        public string prop2 { get; set; }

    }
    public class Program
    {
        public static void Main(string[] args)
        {
            //Creating Class Object
            class1 objClass1 = new class1 { prop1 = "value1", prop2 = "value2" };

            //Passing Class Object to GenericPropertyFinder Class
            GenericPropertyFinder<class1> objGenericPropertyFinder = new GenericPropertyFinder<class1>();
            objGenericPropertyFinder.PrintTModelPropertyAndValue(objClass1);
            Console.ReadLine();
        }

        //Declaring a Generic Handler Class which will actually give Property Name,Value for any given class.
        public class GenericPropertyFinder<TModel> where TModel : class
        {
            public void PrintTModelPropertyAndValue(TModel tmodelObj)
            {
                //Getting Type of Generic Class Model
                Type tModelType = tmodelObj.GetType();

                //We will be defining a PropertyInfo Object which contains details about the class property 
                PropertyInfo[] arrayPropertyInfos = tModelType.GetProperties();

                //Now we will loop in all properties one by one to get value
                foreach (PropertyInfo property in arrayPropertyInfos)
                {
                    Console.WriteLine("Name of Property is\t:\t" + property.Name);
                    Console.WriteLine("Value of Property is\t:\t" + property.GetValue(tmodelObj).ToString());
                    Console.WriteLine(Environment.NewLine);
                }
            }
        }
    }
}
vibs2006
  • 6,028
  • 3
  • 40
  • 40
-1

Hey guys ive been struggeling with the same issue with generic typs and finally found the solution that gets the value --------Small code snippet of the method that does the trick ------------------

    public void printFields()
    {
        // Is the list empty
        if (this.list_.Count == 0)
        {
            //Y => Forced exit no object info
            return;
        }

        try
        {
            // Get first item from list
            T item = this.list_[0];

            // Get the type of object
            //**Type thisType = item.GetType();

            // Get array of all fields
            FieldInfo[] thisFieldInfo = item.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            // Loop through all fields and show its info
            for (int ix = 0; ix < thisFieldInfo.Length; ix++)
            {
                // Get Field value
                String strVal = thisFieldInfo[ix].GetValue(item).ToString();

                // Display item
                Console.WriteLine("'{0}' is a {1} and has value {2}", thisFieldInfo[ix].Name, thisFieldInfo[ix].FieldType, strVal);
            }


        }
        catch (SecurityException e)
        {
            Console.WriteLine("Exception: " + e.Message);
        }
    }