Получить свойство универсального класса

У меня есть общий класс и значение объекта, где obj.GetType().GetGenericTypeDefinition() == typeof(Foo<>).

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

Как получить значение Items из obj? Помните, что obj - это Object, я не могу отличить obj как Foo, потому что я не знаю, что такое T.

Я надеялся использовать отражение для этого, но каждый раз, когда я делаю GetProperty("Items"), он возвращает null. Однако, если кто-то знает хороший способ сделать это без отражения, во что бы то ни стало.

Скажем, мой код выглядит следующим образом:

//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 null

Ответы

Ответ 1

Вы должны иметь возможность использовать:

Type t = obj.GetType();

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

object list = prop.GetValue(obj);

Вы не сможете отличить как List<T>, конечно, так как вы не знаете тип T, но вы все равно сможете получить значение Items.


Edit:

Ниже приведен полный пример для демонстрации этой работы:

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

Ответ 2

@ReedCopsey абсолютно корректен, но в случае, если вы действительно задаете вопрос "Как я могу вырезать общие детали типа?", здесь некоторые "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);
    }
}

Ответ 3

Что-то вроде этого должно сделать трюк:

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

Ответ 4

Для успешного выполнения программы вам необходимо использовать пространство имен System.Reflection.

Эта программа дает вам Имя свойства и значение любого общего класса

Вы можете проверить этот скрипт кода на С# Online Rexter Tool Compiler в

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