Как получить свойство Count, используя отражение для универсальных типов - PullRequest
9 голосов
/ 06 января 2011

У меня есть список объектов, тип которых я не могу знать во время компиляции.

Мне нужно идентифицировать любой из этих объектов, где существует свойство 'Count', и получить значение, еслиэто так.

Этот код работает для простых типов коллекций:

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

Проблема в том, что это не работает для универсальных типов, таких как IDictionary<TKey,TValue>.В этих случаях значение countProperty возвращается как ноль, даже если свойство экземпляра существует в экземпляре объекта.

Все, что я хочу сделать, - это определить любой объект на основе коллекции / словаря и найти его размер, если он есть.

Редактировать: по запросу, вот полный список кода, который не работает

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 ]

12 голосов
/ 06 января 2011

Первое, что вы должны попробовать, это приведение к ICollection, так как это очень дешево .Count:

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

Хотя Count для словаря должно работать - я это проверялс Dictionary<,> и работает нормально - но учтите, что даже если что-то реализует IDictionary<,>, тип concrete (возвращаемый через GetType()) не обязательно должен иметь .Count в общедоступном API - он может использовать явную реализацию интерфейса для удовлетворения интерфейса, в то время как не с 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;
        }
    }
}
2 голосов
/ 12 января 2011

Как насчет добавления этого после первой проверки (! Не проверено!) ...

foreach (Type interfaceType in objectValue.GetType().GetInterfaces())
{
    countProperty = interfaceType.GetProperty("Count");
    //etc.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...