【问题标题】:Getting all ICollection properties through reflection通过反射获取所有 ICollection 属性
【发布时间】:2014-08-27 04:47:10
【问题描述】:

我正在尝试从未知类型的类中获取所有 ICollection<T> 属性。此外,类型 T(集合是什么)在编译时是未知的。首先我尝试过这种方法:

foreach (var property in entity.GetType().GetProperties())
{
    if (typeof(ICollection).IsAssignableFrom(property.PropertyType) || typeof(ICollection<>).IsAssignableFrom(property.PropertyType))
    {
        // do something
    }
}

但它不起作用(即使 ICollection 属性也评估为 false)。

我是这样工作的:

foreach (var property in entity.GetType().GetProperties())
{
    var getMethod = property.GetGetMethod();
    var test = getMethod.Invoke(entity, null);
    if (test is ICollection)
    {
        // do something
    }
}

但我不想执行所有吸气剂。为什么第一段代码不起作用?如何在不执行所有 getter 的情况下找到 ICollection 属性?

【问题讨论】:

  • ICollection 和 ICollection&lt;T&gt; 是不同的类型。你真正对哪个感兴趣?
  • 我只对 ICollection 属性感兴趣(例如 public virtual ICollection Notes { get; set; })。在使用 EF 和 POCO(分离)对象时,我正在尝试解决具有多对多关系的添加/更新对象。为此,我需要获取任何类(未知)的 ICollection 属性,然后获取该属性的值,即集合的元素。
  • 反射很慢。您是否考虑过将 T4 用于代码生成?然而,这感觉非常 XY,我怀疑你可以用泛型解决你的大部分实际问题......PS 你有没有考虑过你将如何处理循环关系?

标签: c# reflection


【解决方案1】:

原来用IsAssignableFrom检查你找不到接口是否是另一个接口的派生:

Console.WriteLine(typeof(ICollection<>).IsAssignableFrom(typeof(ICollection<Int32>)));     
Console.WriteLine(typeof(ICollection<Int32>).IsAssignableFrom(typeof(ICollection<>)));

都会写false;

在here 的帮助下,这是我能想到的最佳解决方案:

    static IEnumerable<PropertyInfo> GetICollectionOrICollectionOfTProperties(this Type type)
    {    
        // Get properties with PropertyType declared as interface
        var interfaceProps =
            from prop in type.GetProperties()
            from interfaceType in prop.PropertyType.GetInterfaces()
            where interfaceType.IsGenericType
            let baseInterface = interfaceType.GetGenericTypeDefinition()
            where (baseInterface == typeof(ICollection<>)) || (baseInterface == typeof(ICollection))
            select prop;

        // Get properties with PropertyType declared(probably) as solid types.
        var nonInterfaceProps =
            from prop in type.GetProperties()
            where typeof(ICollection).IsAssignableFrom(prop.PropertyType) || typeof(ICollection<>).IsAssignableFrom(prop.PropertyType)
            select prop;

        // Combine both queries into one resulting
        return interfaceProps.Union(nonInterfaceProps);                
    }

此解决方案可能会产生一些重复(几乎不可能,但请务必使用Distinct)并且看起来不太好。

但它适用于具有接口返回类型和具体返回类型的属性的此类:

    class Collections
    {
        public List<Int32> ListTProp
        {
            get;
            set;
        }

        public IDictionary<Int32, String> IDictionaryProp
        {
            get;
            set;
        }

        public ICollection ICollectionProp
        {
            get;
            set;
        }

        public ICollection<DateTime> IDateTimeCollectionProp
        {
            get;
            set;
        }
    }

【讨论】:

  • @Askolein 也许,它不能解决 OP 面临的确切问题,或者以他不想使用的方式解决它。或者,也许,他只是忘记将其标记为已接受。谁知道呢。
【解决方案2】:

在尝试使用已接受的答案后,我遇到了一种情况,即仅返回部分匹配项。我的对象有 3 个 ICollection&lt;T&gt; 属性,而我只返回了 2 个。我花了一些时间测试并试图找出原因,但我继续写了这个:

public static IEnumerable<PropertyInfo> GetICollectionProperties(object entity) 
{
    return entity.GetType().GetProperties()
            .Where(p => p.PropertyType.IsGenericType
            && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>));
}

我已经用相同的测试用例进行了测试,我得到了从这个方法返回的正确结果。

这不会选择非通用 ICollections,但 OP 确实要求提供 ICollection&lt;T&gt;properties,尽管它可以很容易地重新分解以包含在内。它也不会返回不完全属于 ICollection 类型的属性(即,在他的测试用例中,Eugene 的 List 和 IDictionary 不会被返回(但同样是 OP 想要的)。

【讨论】:

    猜你喜欢
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多