如何使用反射为通用类型获取Count属性

时间:2011-01-06 07:05:18

标签: c# reflection

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

我需要识别存在'Count'属性的任何这些对象,如果存在则获取值。

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

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

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

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

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

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只是一个包含缓存项属性的简单类 - 即密钥,计数,类型,到期日期时间

2 个答案:

答案 0 :(得分:12)

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

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

字典的Count应该可以正常工作 - 我已经使用Dictionary<,>进行了测试,但它运行正常 - 但请注意,即使某些内容实现IDictionary<,>具体< / em> type(通过GetType()返回)必须在公共API上有.Count - 它可以使用显式接口实现拥有public int Count {get;}时满足界面要求。就像我说的:它适用于Dictionary<,> - 但不一定适用于所有类型。

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

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

编辑以查看评论中提出的Dictionary<,>问题:

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

答案 1 :(得分:2)

第一次检查后添加此内容(!未经测试!)......

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