Преобразовать последовательность массивов T myArray [] в IEnumerable <T>в c # - PullRequest
1 голос
/ 28 февраля 2011

В следующем коде я хочу вернуть IEnumerable без создания нового объекта структуры данных. Тем не менее, я получаю ошибку компилятора с помощью следующего кода. Что мне не хватает?

Error       Cannot implicitly convert type 'System.Reflection.FieldInfo[]' to 'System.Reflection.FieldInfo' 

public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
   while (objectType != null)
   {
      //GetFields(...) returns a FieldInfo []
      yield return objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
      objectType = objectType.BaseType;
   }
}

Ответы [ 6 ]

4 голосов
/ 28 февраля 2011

Type.GetFields возвращает массив объектов FieldInfo.

Поскольку вы не возвращаете коллекцию массивов, вы должны выполнить итерацию по массиву и привести к возвращению каждого объекта в нем, например, так:

foreach (var fi in objectType.GetFields(...))
    yield return fi;
4 голосов
/ 28 февраля 2011

yield return работает на отдельных элементах;вы можете просто вернуть возвращаемое значение из GetFields, чтобы достичь желаемого.

Для более подробного объяснения yield return в основном полезно, когда вы хотите применить некоторую операцию к каждому элементу в последовательности перед тем, как сделать его доступным.вызывающей стороне, но вы не хотите выполнять всю эту работу заранее и просто возвращаете агрегированные результаты в массив или List<T>.

yield return делает это отложенное выполнение легко написать, потому что сгенерированный блок итератора применяет любую такую ​​операцию только к каждому элементу, как он запрашивается.

РЕДАКТИРОВАТЬ: Извините - я пропустил один из пунктов вашего кода (перечислениебазовые поля), но я оставлю этот ответ, так как думаю, что он может быть полезен в любом случае.Ответ Лассе Карлсена будет делать то, что вам нужно, но если у вас нет огромной иерархии типов, вы не получите никакого преимущества по сравнению с простым объединением результатов и возвратом их в массив.

1 голос
/ 28 февраля 2011

Вы можете попробовать рекурсию + Concat:

public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
   if (objectType == null)
      return Enumerable<FieldInfo>.Empty;
   else 
      return objectType.GetFields(
                 BindingFlags.NonPublic | BindingFlags.Public |
                 BindingFlags.Instance | BindingFlags.DeclaredOnly)
         .Concat(GetAllFields(objectType.BaseType));
}
0 голосов
/ 28 февраля 2011

Как все отметили, проблема в том, что тип полученного элемента не совпадает с ожидаемым типом.

Чтобы не писать каждый раз for / while / foreach, мне нравится использовать метод расширения, который обрабатывает итерацию для меня.

public static class Sequence
{
    public static IEnumerable<T> Create<T>(T seed, Func<T, bool> predicate, Func<T, T> next)
    {
        for (T t = seed; predicate(t); t = next(t))
            yield return t;
    }
}

Таким образом, вы можете вернуть поля, написав гораздо более читаемый запрос

public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
    BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
    return from type in Sequence.Create(objectType, t => t != null, t => t.BaseType)
        from field in type.GetFields(flags)
        select field;
}
0 голосов
/ 28 февраля 2011

Как насчет небольшой рекурсии?

public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{      
      //GetFields(...) returns a FieldInfo []
      var fields = objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
      if(objectType.BaseType==null) return fields;
      return fields.Concat(GetAllFields(object.BaseType));
 }
0 голосов
/ 28 февраля 2011

То, что вы ищете, это «доходность за все». Вам нужно будет выполнить foreach и вернуть return для каждого элемента, возвращенного из GetFields, а затем установить базовый класс.

Это не должно быть необходимым, потому что есть флаг для того, включать или нет определения базового класса.

...