迭代索引属性(反射)

时间:2010-11-24 15:08:14

标签: c# .net reflection

我想对一个只能通过反射访问的索引属性进行迭代,

但是(我完全知道这可能是一个令人尴尬的简单答案,MSDN / Google失败= /)除了PropertyInfo.GetValue(prop, counter)之前递增一个计数器,我找不到/想到一种方法直到{ {1}}被抛出。

ALA:

TargetInvocationException

现在,这有一些问题...非常难看..解决方案..

如果它是多维的或者没有被整数索引,例如......

继承了我正在使用的测试代码,如果有人需要它,可以让它运行起来。如果有人有兴趣我正在制作一个自定义缓存系统而且.Equals不会削减它。

foreach ( PropertyInfo prop in obj.GetType().GetProperties() )
{
    if ( prop.GetIndexParameters().Length > 0 )
    {
        // get an integer count value, by incrementing a counter until the exception is thrown
        int count = 0;
        while ( true )
        {
            try
            {
                prop.GetValue( obj, new object[] { count } );
                count++;
            }
            catch ( TargetInvocationException ) { break; }
        }

        for ( int i = 0; i < count; i++ )
        {
            // process the items value
            process( prop.GetValue( obj, new object[] { i } ) );
        }
    }
}

6 个答案:

答案 0 :(得分:8)

索引器的getter就像普通方法一样,除了它采用方括号而不是圆括号。您不希望能够自动确定方法的可接受值范围,因此对于索引器来说这是不可行的。

答案 1 :(得分:4)

将索引器编译为方法。这是一个例子:

class IndexedData
{ 
    public double this[int index]
    {
        get { return (double)index; }
    }
}

它将被编译为类似的东西:

public double get_Item(int index)
{
    return (double)index;
}

以下代码无法编译,因为类中有两个double get_Item(int)方法。 Indexer是编译器的神奇之处。

class IndexedData
{ 
    public double this[int index]
    {
        get { return (double)index; }
    }

    public double get_Item(int index)
    {
        return 1d;
    }
}

答案 2 :(得分:3)

在索引属性中包含连续的索引号是没有什么可以打赌的 索引属性不是数组 反例:

Dictionary<int, bool> dictionary = new Dictionary<int, bool>();
dictionary[1] = true;
dictionary[5] = false;

根据类型,您通常有其他方法来获取可能的索引值,在本例中为dictionary.Keys。如果可以使用您的类型,我会按此顺序尝试

  1. 为类型本身实施IEnumerable<T>
  2. 如果您有多个索引属性,则可以为每个索引属性实现相应的IEnumerable<T>属性。
  3. 如果你没有有效值的说明,也没有询问有效值是什么的方法,那么你几乎没有运气。

答案 3 :(得分:2)

您可以使用PropertyInfo.GetIndexParameters查找索引属性参数的数量和类型。

我不认为你可以做些什么来找到这些参数的“合法”值,除非你“欺骗”并使用你可能拥有的内幕信息。

答案 4 :(得分:2)

管理进行改进,介意,还发现这个测试代码遭受自我引用的无限循环(例如Array.Syncroot)

简而言之,它现在发现从IEnumerable继承的东西(这是大多数索引的东西),并在那些上使用foreach循环,再加上现有(丑陋)代码适用于字符串的知识,它现在分配得更彻底曾经是......

很高兴,但似乎没有一个好的答案。

感谢大家的帮助


如果有人发现自己处于类似的位置,则更新测试代码

    static void process( object obj )
    {
        Type type = obj.GetType();

        PropertyInfo[] properties = type.GetProperties();

        // if this obj has sub properties, apply this process to those rather than this.
        if ( properties.Length > 0 )
        {
            foreach ( PropertyInfo prop in obj.GetType().GetProperties() )
            {
                    if ( prop.PropertyType.FindInterfaces( ( t, c ) => t == typeof( IEnumerable ), null ).Length > 0 )
                    {
                        MethodInfo accessor = prop.GetGetMethod();
                        MethodInfo[] accessors = prop.GetAccessors();

                        foreach ( object item in (IEnumerable)obj )
                        {
                            process( item );
                        }
                    }
                    else if ( prop.GetIndexParameters().Length > 0 )
                    {
                        // get an integer count value, by incrementing a counter until the exception is thrown
                        int count = 0;
                        while ( true )
                    {
                        try
                        {
                            prop.GetValue( obj, new object[] { count } );
                            count++;
                        }
                        catch ( TargetInvocationException ) { break; }
                    }

                    for ( int i = 0; i < count; i++ )
                    {
                        // process the items value
                        process( prop.GetValue( obj, new object[] { i } ) );
                    }
                }
                else
                {
                    // is normal type so.
                    process( prop.GetValue( obj, null ) );
                }
            }
        }
        else
        {
            // process to be applied to each property
            Console.WriteLine( "Property Value: {0}", obj.ToString() );
        }
    }

答案 5 :(得分:0)

上述代码和此问题的相关内容对我所面临的问题非常有帮助。我发布了我的代码,我希望这个代码也适用于你们。

public ActionResult Survey(SurveyCollection surveyCollection) { if (surveyCollection != null) { Answer_DropDownCordinateOptionList traceObject = new Answer_DropDownCordinateOptionList(); IList traceObjectCollection = new List(); traceObjectCollection = ExtractNestedObjects(surveyCollection, traceObject, traceObjectCollection); }

    return View(surveyCollection);
}

private static IList<T> ExtractNestedObjects<T>(object baseObject, T findObject, IList<T> resultCollection)
{
    if (baseObject != null && findObject != null)
    {
        Type typeDestination = findObject.GetType();

        Type typeSource = baseObject.GetType();
        PropertyInfo[] propertyInfoCollection = typeSource.GetProperties();
        foreach (PropertyInfo propertyInfo in propertyInfoCollection)
        {
            if (propertyInfo.PropertyType.FindInterfaces((t, c) => t == typeof(IEnumerable), null).Length > 0)
            {
                if(propertyInfo.GetValue(baseObject, null) != null)
                {
                    if(propertyInfo.GetValue(baseObject, null).GetType().IsPrimitive)
                    {
                        ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection);
                    }
                    else if (propertyInfo.GetValue(baseObject, null).GetType().IsGenericType)
                    {
                        foreach (var item in (IList)propertyInfo.GetValue(baseObject, null))
                        {
                            ExtractNestedObjects<T>(item, findObject, resultCollection);
                        }
                    }
                }
            }
            else
            {
                if (propertyInfo.Name == typeDestination.Name)
                {
                    if (propertyInfo.GetValue(baseObject, null) != null)
                    {
                        resultCollection.Add((T)propertyInfo.GetValue(baseObject, null));
                    }
                }

                ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection);
            }
        }
    }
    return resultCollection;
}

return View(surveyCollection); } private static IList<T> ExtractNestedObjects<T>(object baseObject, T findObject, IList<T> resultCollection) { if (baseObject != null && findObject != null) { Type typeDestination = findObject.GetType(); Type typeSource = baseObject.GetType(); PropertyInfo[] propertyInfoCollection = typeSource.GetProperties(); foreach (PropertyInfo propertyInfo in propertyInfoCollection) { if (propertyInfo.PropertyType.FindInterfaces((t, c) => t == typeof(IEnumerable), null).Length > 0) { if(propertyInfo.GetValue(baseObject, null) != null) { if(propertyInfo.GetValue(baseObject, null).GetType().IsPrimitive) { ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection); } else if (propertyInfo.GetValue(baseObject, null).GetType().IsGenericType) { foreach (var item in (IList)propertyInfo.GetValue(baseObject, null)) { ExtractNestedObjects<T>(item, findObject, resultCollection); } } } } else { if (propertyInfo.Name == typeDestination.Name) { if (propertyInfo.GetValue(baseObject, null) != null) { resultCollection.Add((T)propertyInfo.GetValue(baseObject, null)); } } ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection); } } } return resultCollection; }