【问题标题】:Determine if a property is a kind of array by reflection通过反射判断一个属性是否是一种数组
【发布时间】:2012-02-24 16:58:30
【问题描述】:

如何确定一个属性是否是一种数组。

例子:

public bool IsPropertyAnArray(PropertyInfo property)
{
    // return true if type is IList<T>, IEnumerable<T>, ObservableCollection<T>, etc...
}

【问题讨论】:

  • 所以你的意思是,如果属性是一个集合?与您的评论匹配的东西不是数组。
  • 您的意思可能是IEnumerable 而不是IEnumerator
  • @Ben:好吧,数组符合他的标准(IList 和 IEnumerable),但并非所有符合他标准的东西都是数组。 :)

标签: c# reflection


【解决方案1】:

您似乎在问两个不同的问题:一个类型是数组(例如string[])还是任何集合类型。

对于前者,只需检查property.PropertyType.IsArray

对于后者,您必须确定您希望类型符合的最低标准是什么。例如,您可以使用typeof(IEnumerable).IsAssignableFrom(property.PropertyType) 检查非通用IEnumerable。如果您知道 T 的实际类型,也可以将其用于泛型接口,例如typeof(IEnumerable&lt;int&gt;).IsAssignableFrom(property.PropertyType).

检查泛型IEnumerable&lt;T&gt; 或任何其他泛型接口而不知道T 的值可以通过检查property.PropertyType.GetInterface(typeof(IEnumerable&lt;&gt;).FullName) 是否不是null 来完成。请注意,我没有在该代码中为 T 指定任何类型。您可以对IList&lt;T&gt; 或您感兴趣的任何其他类型执行相同的操作。

例如,如果您想检查通用 IEnumerable&lt;T&gt;,您可以使用以下代码:

public bool IsPropertyACollection(PropertyInfo property) 
{ 
    return property.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) != null;
} 

数组也实现了 IEnumerable,因此它们也会从该方法返回 true

【讨论】:

  • 这个实现会错过“old school collections”,它继承自 .Net 1,它实现了 IEnumerable,但不是通用版本的 IEnumerable。它们的使用越来越少,但一些 API 期望它们,它们真的很痛苦。
  • @Falanwe:然后使用我提到的第一种方法,它确实检查非泛型 IEnumerable。这真的取决于他的要求,哪个是最好的。
  • 我用一个字符串属性尝试你的方法,该方法返回 true...你知道为什么吗?
  • @Melursus:String 类实现了IEnumerable&lt;char&gt;,因此它符合这些标准的集合。您要么需要专门过滤掉它,要么检查限制性更强的接口(例如ICollection&lt;T&gt;IList&lt;T&gt;)。
  • 当然,任何实现泛型IEnumerable&lt;&gt; 的类型也将是非泛型IEnumerable
【解决方案2】:

排除 String 类,因为它实现了 IEnumerable&lt;char&gt;,因此它有资格作为一个集合。

public bool IsPropertyACollection(this PropertyInfo property)
{
    return (!typeof(String).Equals(property.PropertyType) && 
        typeof(IEnumerable).IsAssignableFrom(property.PropertyType));
}

【讨论】:

  • typeof(String) 是我遗漏的支票
【解决方案3】:

如果你想知道属性是不是数组,其实很简单:

property.PropertyType.IsArray;

编辑

如果你想知道它是否是实现 IEnumerable 的类型,就像所有“集合类型”一样,也不是很复杂:

return property.PropertyType.GetInterface("IEnumerable") != null;

【讨论】:

  • 我不确定这是否是 OP 真正想要的(但我承认命名有点误导)。实现 IList&lt;T&gt; 的自定义类型将从该属性返回 false。
  • 确实,我最初误读了这个问题。我编辑了答案以包含任何 IEnumerable
  • @Falanwe: IsSubclassOf 不适用于接口,只能用于基类。
  • @Falanwe:我看不懂法语,但英文版说“IsSubclassOf 方法不能用于确定一个接口是否派生自另一个接口,或者类实现了一个接口”(强调我的)。
  • @Sven:你说得对,我读文档太快了。我编辑了我的答案
【解决方案4】:
    public static bool IsGenericEnumerable(Type type)
    {
        return type.IsGenericType && 
            type.GetInterfaces().Any(
            ti => (ti == typeof (IEnumerable<>) || ti.Name == "IEnumerable"));
    }

    public static bool IsEnumerable(Type type)
    {
        return IsGenericEnumerable(type) || type.IsArray;
    }

【讨论】:

    【解决方案5】:

    对我来说,以下不起作用,

    return property.PropertyType.GetInterface(typeof(ICollection<>).FullName) != null;
    

    以下工作正常,

    typeof(ICollection<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition())
    

    这是检查ICollection&lt;IInterface&gt;ICollection&lt;BaseClassInTree&gt;的快捷方式

    var property = request as PropertyInfo;
    
    property.PropertyType.IsGenericType && (typeof(ICollection<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition())) && typeof().IsAssignableFrom(property.PropertyType.GenericTypeArguments[0])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-29
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多