Индексированные свойства отражения C#

Я пишу метод Clone, используя отражение. Как с помощью отражения определить, что свойство является индексированным? Например:

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

person Greg Finzer    schedule 14.11.2008    source источник
comment
Это не индексированное свойство, это свойство, которое возвращает массив.   -  person Jason Jackson    schedule 15.11.2008
comment
Этот вопрос должен быть изменен модератором. Это лучший результат Google для поиска свойства индексатора, но это не то, что иллюстрирует пример кода. Половина приведенных ниже ответов отвечает на вопрос, а половина — на пример кода.   -  person Ben Gripka    schedule 21.02.2015


Ответы (5)


Извините, но

public string[] Items { get; set; }

является не индексированным свойством, это просто тип массива! Однако следующее:

public string this[int index]
{
    get { ... }
    set { ... }
}
person Community    schedule 13.01.2009
comment
Хорошо, но как найти его с помощью отражения? - person BrainSlugs83; 07.03.2014

Вам нужен метод GetIndexParameters(). Если массив, который он возвращает, содержит более 0 элементов, это означает, что это индексированное свойство.

Дополнительные сведения см. в документации MSDN.

person Jeromy Irvine    schedule 14.11.2008

Если вы вызываете property.GetValue(obj,null), а свойство индексируется, вы получите исключение несоответствия количества параметров. Лучше проверить, индексируется ли свойство с помощью GetIndexParameters(), а затем решить, что делать.

person John Holliday    schedule 17.06.2011

Вот код, который работал у меня:

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 для значения типа string, используйте его, но оно не работает для большинства интересующих меня массивов, включая Я почти уверен, массив строк из исходного вопроса.

person ILIA BROUDNO    schedule 07.06.2011

Вы можете преобразовать индексатор в 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);
    }
person Krzysztof Radzimski    schedule 02.07.2013
comment
Я думаю, что это обрабатывает только свойства одиночного целочисленного индексатора, верно? нет индексаторов на основе строк, нет множественных параметров индекса... или я что-то упустил? - person Code Jockey; 14.08.2014
comment
@CodeJockey — возможно, вы правы; У меня возникли проблемы с работой с типом ввода String. Он зависает на индексированном свойстве Chars. Если я сам чего-то не упустил... - person InteXX; 21.01.2017