【问题标题】:Get property of generic class获取泛型类的属性
【发布时间】:2012-12-17 06:07:35
【问题描述】:

我有一个泛型类和一个对象值,其中obj.GetType().GetGenericTypeDefinition() == typeof(Foo<>)。

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

如何从obj 获取Items 的值?请记住,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's null

【问题讨论】:

  • 你在 typeof(Foo) 上调用 GetProperty() 吗?
  • GetProperty 应该没问题。请发布一个简短但完整的程序来演示该问题。如果您使用的是 .NET 4,dynamic 也可以很好地工作。
  • @JonSkeet 抱歉,我使用的是 3.5。上面的示例代码。
  • 使用你的(几乎)准确的code with .Net 3.5 and MS VC# 2k8 works just fine。
  • @gunr2171:您的示例无法编译,并且在应用了明显的修复后,GetProperty 不 返回 null。请展示一个简短但完整的程序确实实际演示了问题。

标签: c#


【解决方案1】:

你应该可以使用:

Type t = obj.GetType();

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

object list = prop.GetValue(obj);

当然,您将无法直接转换为List&lt;T&gt;,因为您不知道T 的类型,但您仍然应该能够获得Items 的值。


编辑:

下面是一个完整的例子,用来演示这个工作:

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

【讨论】:

  • 您仍然可以将其转换为 IList。
  • @luksan 是,或者ICollection 和IEnumerable。
  • 您需要使用GetValue(obj, null),具体取决于框架版本。
  • 我很乐意让最终结果(Items 的值)成为一个对象。此外,此代码将为我返回 null。
  • @gunr2171 如果您的 Items 集合不为空,这应该可以工作。您是否已验证 Items 在您的 obj 实例中不为空?
【解决方案2】:

@ReedCopsey 是绝对正确的,但如果你真的在问“我如何找出一个类型的通用细节?”,这里有一些“反射的乐趣”:

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

【讨论】:

  • 所以我不确定这是否是您的代码,但这是第一个使它工作的代码。 (不知道为什么你在这里有 -1,按照我的标准很好)
  • @gunr2171 嗯,可能是因为我并没有试图真正回答所述问题...*耸耸肩* 我不在乎反对票,但是我喜欢谈论整洁的代码。 :)
  • @sixlettervariables 点,虽然可以说我的回答,虽然不是 100% 直接针对原始问题,但确实回答了如何反映类型的通用参数的推断问题。我承认,我的“整洁代码”评论相当轻率。
  • @sixlettervariables 同样,不是不同意,而是在最初的问题中:“我不能将 obj 转换为 Foo 因为我不知道 T 是什么。”和“假设我不知道 是什么”-> 向我暗示,如果你有无类型(好吧,未绑定的泛型)版本,他在问如何确定泛型类的类型化变体.....Of当然,现在我只是在迂腐;我完全承认,鉴于各种更新,我在这里得到的代码完全没有必要。
  • @JerKimball 你的代码帮助我解决了另一个问题,谢谢!
【解决方案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 命名空间才能成功执行程序。

    此程序为您提供任何通用类的属性名称和值

    您可以在C# 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);
                    }
                }
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      大家好,我一直在为通用类型的相同问题而苦苦挣扎,终于找到了有价值的解决方案 --------实现技巧的方法的小代码sn-p ------

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-15
        • 2015-07-28
        • 2020-01-29
        • 2018-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多