【问题标题】:How to get the Count property using reflection for Generic types如何使用泛型类型的反射获取 Count 属性
【发布时间】:2011-01-06 07:05:18
【问题描述】:

我有一个对象列表,在编译时我无法知道其类型。

我需要识别任何存在“计数”属性的对象,如果存在则获取值。

此代码适用于简单的集合类型:

PropertyInfo countProperty = objectValue.GetType().GetProperty("Count");
 if (countProperty != null)
 {
     int count = (int)countProperty.GetValue(objectValue, null);
 }

问题在于这不适用于泛型类型,例如IDictionary<TKey,TValue>。在这些情况下,“countProperty”值返回为 null,即使实例对象中存在“Count”属性。

我要做的就是识别任何基于集合/字典的对象并找到它的大小(如果有的话)。

编辑:根据要求,这是不起作用的代码的完整列表

private static void GetCacheCollectionValues(ref CacheItemInfo item, object cacheItemValue)
{
    try
        {
        //look for a count property using reflection
        PropertyInfo countProperty = cacheItemValue.GetType().GetProperty("Count");
        if (countProperty != null)
        {
            int count = (int)countProperty.GetValue(cacheItemValue, null);
            item.Count = count;
        }
        else
        {
            //poke around for a 'values' property
            PropertyInfo valuesProperty = cacheItemValue.GetType().GetProperty("Values");
            int valuesCount = -1;
            if (valuesProperty != null)
            {
                object values = valuesProperty.GetValue(cacheItemValue, null);
                if (values != null)
                {
                    PropertyInfo valuesCountProperty = values.GetType().GetProperty("Count");
                    if (countProperty != null)
                    {
                        valuesCount = (int)valuesCountProperty.GetValue(cacheItemValue, null);
                    }
                }
            }
            if (valuesCount > -1)
                item.Count = valuesCount;
            else
                item.Count = -1;
        }
    }
    catch (Exception ex)
    {
        item.Count = -1;
        item.Message = "Exception on 'Count':" + ex.Message;
    }
}

这适用于简单的集合,但不适用于从我拥有的从Dictionary<TKey,TValue> 派生的类创建的对象。即

CustomClass : 
    Dictionary<TKey,TValue>

CacheItemInfo 只是一个简单的类,其中包含缓存项的属性 - 即键、计数、类型、到期日期时间

【问题讨论】:

  • (从IDictionary&lt;TKey,TValue&gt; 的角度思考在这里没有帮助,因为GetType() 将始终返回 concrete 类型,它可以是任何东西,但很可能是@ 987654328@)
  • 这是当前的代码 - 仍然无法正常工作。
  • 所以答案是忽略反射并只转换到接口 - 请参阅下面的正确答案。

标签: c# reflection


【解决方案1】:

您应该尝试的第一件事是投射到ICollection,因为这有一个非常便宜的.Count

ICollection col = objectValue as ICollection;
if(col != null) return col.Count;

虽然字典的Count 应该可以工作 - 我已经用Dictionary&lt;,&gt; 测试过它并且工作正常 - 但请注意,即使某些东西实现了IDictionary&lt;,&gt;concrete 类型(返回通过GetType()不需要在公共API上必须有.Count - 它可以使用显式接口实现来满足接口,而不 拥有public int Count {get;}。就像我说的:它适用于 Dictionary&lt;,&gt; - 但不一定适用于所有类型。

如果其他一切都失败了,作为最后的努力:

IEnumerable enumerable = objectValue as IEnumerable;
if(enumerable != null)
{
    int count = 0;
    foreach(object val in enumerable) count++;
    return count;
}

编辑以查看 cmets 中提出的 Dictionary&lt;,&gt; 问题:

using System;
using System.Collections;
using System.Collections.Generic;
public class CustomClass : Dictionary<int, int> { }
public class CacheItemInfo
{
    public int Count { get; set; }
    public string Message { get; set; }
}
class Program {
    public static void Main() {
        var cii = new CacheItemInfo();
        var data = new CustomClass { { 1, 1 }, { 2, 2 }, { 3, 3 } };
        GetCacheCollectionValues(ref cii, data);
        Console.WriteLine(cii.Count); // expect 3
    }
    private static void GetCacheCollectionValues(ref CacheItemInfo item, object cacheItemValue)
    {
        try
        {
            ICollection col;
            IEnumerable enumerable;
            if (cacheItemValue == null)
            {
                item.Count = -1;
            }
            else if ((col = cacheItemValue as ICollection) != null)
            {
                item.Count = col.Count;
            }
            else if ((enumerable = cacheItemValue as IEnumerable) != null)
            {
                int count = 0;
                foreach (object val in enumerable) count++;
                item.Count = count;
            }
            else
            {
                item.Count = -1;
            }
        }
        catch (Exception ex)
        {
            item.Count = -1;
            item.Message = "Exception on 'Count':" + ex.Message;
        }
    }
}

【讨论】:

  • 马克 - 感谢您的贡献。我发现我从最初的问题中省略了重要的细节——我正在查看的类之一派生自 Dictionary,这是不与 .Count() 一起使用的类之一。您提到使用 IDictionary 进行测试 - 您可以发布您使用的代码吗?
  • @Bruce - 我用Dictionary&lt;,&gt; 进行了测试 - 具体类型(接口与GetType() 直接无关 - 它仍然应该与它的子类一起使用。你能显示代码 不行?我刚刚传入了一本字典。
  • Marc - 很抱歉延误了无论如何都必须发货。我已经发布了我正在使用的完整代码,它仍然不适用于字典项。
  • @Bruce - 重新编辑; nothing 在我的回答中根本没有提到反射。我检查了您的CustomClass 设置(见上文),它正常工作,完美地落入ICollection 代码中。
  • 哦 - 我没有注意到你发布了额外的代码,很抱歉。我依赖电子邮件通知而不是查看网站的错误。我会尽快试用代码并通知您。
【解决方案2】:

在你第一次检查之后添加这个怎么样 (!untested!) ...

foreach (Type interfaceType in objectValue.GetType().GetInterfaces())
{
    countProperty = interfaceType.GetProperty("Count");
    //etc.
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 2018-06-05
    • 2012-09-23
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    • 1970-01-01
    相关资源
    最近更新 更多