C# 反射 索引器属性

23

我正在使用反射编写一个克隆方法。如何使用反射检测属性是否为索引属性?例如:

public string[] Items
{
   get;
   set;
}

到目前为止,我的方法是:

public static T Clone<T>(T from, List<string> propertiesToIgnore) where T : new()
{
    T to = new T();

    Type myType = from.GetType();

    PropertyInfo[] myProperties = myType.GetProperties();

    for (int i = 0; i < myProperties.Length; i++)
    {
        if (myProperties[i].CanWrite && !propertiesToIgnore.Contains(myProperties[i].Name))
        {
            myProperties[i].SetValue(to,myProperties[i].GetValue(from,null),null);
        }
    }

    return to;
}

13
那不是一个索引属性,而是一个返回数组的属性。 - Jason Jackson
8
这个问题需要由管理员进行修改。它是寻找索引器属性的顶级谷歌搜索结果,但代码示例并不说明这一点。下面一半的答案回答了这个问题,另一半则是关于代码示例的解答。 - Ben Gripka
6个回答

52
if (propertyInfo.GetIndexParameters().Length > 0)
{
    // Property is an indexer
}

22

抱歉,但是

public string[] Items { get; set; }

不是索引属性,它只是一个数组类型!但以下是:

public string this[int index]
{
    get { ... }
    set { ... }
}

6
好的,但是你如何通过反射找到它? - BrainSlugs83

9
你需要的是 GetIndexParameters() 方法。如果它返回的数组有多于 0 个项目,那么这就是一个索引属性。
请查看 MSDN 文档 以获取更多详细信息。

3
如果你调用property.GetValue(obj,null),并且这个属性是索引的,那么你会得到一个参数数量不匹配的异常。更好的方法是使用GetIndexParameters()检查属性是否被索引,然后决定该怎么做。

1

这是一些对我有用的代码:

foreach (PropertyInfo property in obj.GetType().GetProperties())
{
  object value = property.GetValue(obj, null);
  if (value is object[])
  {
    ....
  }
}

P.S. .GetIndexParameters().Length > 0) 对于本文中描述的情况有效:http://msdn.microsoft.com/en-us/library/b05d59ty.aspx 因此,如果你关心类型为字符串的值的属性名为Chars,请使用它,但它对我感兴趣的大多数数组都不起作用,包括原始问题中的字符串数组。


1
您可以将索引器转换为IEnumerable。
    public static IEnumerable<T> AsEnumerable<T>(this object o) where T : class {
        var list = new List<T>();
        System.Reflection.PropertyInfo indexerProperty = null;
        foreach (System.Reflection.PropertyInfo pi in o.GetType().GetProperties()) {
            if (pi.GetIndexParameters().Length > 0) {
                indexerProperty = pi;
                break;
            }
        }

        if (indexerProperty.IsNotNull()) {
            var len = o.GetPropertyValue<int>("Length");
            for (int i = 0; i < len; i++) {
                var item = indexerProperty.GetValue(o, new object[]{i});
                if (item.IsNotNull()) {
                    var itemObject = item as T;
                    if (itemObject.IsNotNull()) {
                        list.Add(itemObject);
                    }
                }
            }
        }

        return list;
    }


    public static bool IsNotNull(this object o) {
        return o != null;
    }

    public static T GetPropertyValue<T>(this object source, string property) {
        if (source == null)
            throw new ArgumentNullException("source");

        var sourceType = source.GetType();
        var sourceProperties = sourceType.GetProperties();
        var properties = sourceProperties
            .Where(s => s.Name.Equals(property));
        if (properties.Count() == 0) {
            sourceProperties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
            properties = sourceProperties.Where(s => s.Name.Equals(property));
        }

        if (properties.Count() > 0) {
            var propertyValue = properties
                .Select(s => s.GetValue(source, null))
                .FirstOrDefault();

            return propertyValue != null ? (T)propertyValue : default(T);
        }

        return default(T);
    }

我在想这个只处理单整数索引属性,是吗?没有基于字符串的索引器,没有多个索引参数……或者我漏了什么? - Code Jockey
@CodeJockey — 你可能是正确的;我在使用String输入类型时遇到了问题。它卡在了Chars索引属性上。除非我自己漏掉了什么... - InteXX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接