Получить свойство универсального класса
У меня есть общий класс и значение объекта, где 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);
}
}
}
}
}