【问题标题】:Determine with reflection if a class property is an object that inherits List<T> or any type of collection使用反射确定类属性是继承 List<T> 的对象还是任何类型的集合
【发布时间】:2019-12-11 03:40:03
【问题描述】:

我需要使用反射来过滤掉所有作为集合的对象属性。它们并不总是通用列表,而是一个继承 List&lt;T&gt; 类型的类。例如,我有一个类foo,其属性类型为fooCollectionFooColection 如下所示:

public class foo
{
    public FooCollection myCollection {get;set;}
}

public class fooCollection : List<Foo>
{
}

我不知道List&lt;T&gt; 的类型是什么,但只需要知道它是否是一个集合。我怎样才能找到这个?我问了一个先前的问题,但措辞不同,结果不适用于我的特定实例。

我尝试了以下示例,我查看了foo 的所有属性,并尝试找到fooColelction 的属性:

typeof(IEnumerable<>).IsAssignableFrom(prop.PropertyType)

但这对我来说不能正常工作。类型不是IEnumerable,尽管它是一个集合。它继承了IEnumerable 类型。

这是一个名为 Policy 的类对象的 Collection 类之一的示例。

public class PolicyCollection : List<Policy>
{
    /// <summary>
    /// This function takes a xml Policy collection and builds a PolicyCollection Class
    /// </summary>
    /// <param name="xDocPolicyCollection">XML Document of an PolicyCollection</param>
    protected internal void LoadXml(XmlDocument xDocPolicyCollection)
    {
        foreach (XmlNode n in xDocPolicyCollection.GetElementsByTagName("Policy"))
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(n.OuterXml);

            Policy p = new Policy();
            p.LoadXml(xdoc);
            Add(p);
        }
    }

    /// <summary>
    /// This function takes a datatable of Policies collection and builds a PolicyCollection Class
    /// </summary>
    /// <param name="dtContact">Data</param>
    protected internal void LoadDB(DataTable dtPolicyCollection)
    {
        foreach (DataRow dr in dtPolicyCollection.Rows)
        {
            Policy p = new Policy();
            p.LoadDB(dr);
            Add(p);
        }
    }
}

这与之前的问题不同,因为我要问的是如何检查这种情况下的属性类型是常规类,继承 List&lt;T&gt;,而不是 List&lt;T&gt; 的属性。

【问题讨论】:

  • 能否包含FooCollection 类代码?
  • 是的,一会儿。我将举一个一般的例子来演示。现在,显然这个例子不是 Foo 和 fooCollection,而是针对 Policy 和 PolicyCollection。
  • 为什么需要知道类型是否为列表?这可能是一个 XY 问题。您要解决的实际问题是什么?
  • @CodeCaster 但是再次检查IList 会起作用。我认为 OP 不需要泛型类型参数。
  • 就像@Luaan 说的那样,这说明了 XY 问题。一般来说,您不应该从 List&lt;T&gt; 继承,当然也不应该在单元测试中求助于反射。

标签: c# .net reflection types


【解决方案1】:

主要的问题是一个非具体化的泛型类型(例如IEnumerable&lt;&gt;)可以永远被分配任何东西。 .NET 泛型根本无法以这种方式工作。

相反,您可以使用以下内容:

typeof(PolicyCollection)
.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))

GetInterfaces 返回所有由给定类型实现的接口,然后您只需检查是否有任何IEnumerable&lt;&gt;。通过显式取消具体化找到的泛型接口,我们可以与IEnumerable&lt;&gt;(或IList&lt;&gt; 或您喜欢的任何一个)进行简单的比较。

当然,由于IEnumerable&lt;&gt; 也“需要”IEnumerable,您可以简单地检查它而不是通用接口:

typeof(IEnumerable).IsAssignableFrom(typeof(PolicyCollection));

【讨论】:

  • 我试过这个,但没有用。看到这对我来说很奇怪。为什么它不承认该属性是一个集合。我在 object.GetProperties() 中使用 var prop 来检查类 foo。在那个 foreach 中,我正在对道具进行测试。我使用的是“prop.GetType()”而不是“typeof(PolicyColction)”,因为当时还不知道 T 代表 List
  • @Casey:你需要使用PropertyInfo.PropertyType property,而不是.GetType()PropertyType 将为您提供属性的声明类型,而GetType() 将为您提供prop 的类型(即PropertyInfo
  • 不行,非常抱歉,非常感谢。这帮助我了解了更多关于反思的信息。这就是问题所在。再次感谢!
猜你喜欢
  • 2018-02-22
  • 1970-01-01
  • 2013-07-04
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
相关资源
最近更新 更多