Могу ли я использовать Action <T>для выполнения рекурсивного поиска и возврата IEnumerable указанного свойства? - PullRequest
1 голос
/ 10 декабря 2010

Я написал следующий код для извлечения StructureId s из IEnumerable<Structure>:

Action<Structure> recurse = null;
List<int> structureIds = new List<int>();
recurse = (r) =>
{
    structureIds.Add(r.StructureId);
    r.Children.ForEach(recurse);
};

IEnumerable<Structure> structures = GetStructures();
structures.ForEach(recurse);

Я бы очень хотел сделать это универсальным, чтобы я мог использовать его с любым IEnumerable,то есть что-то вроде:

public static IEnumerable<TType> GetPropertyValues<TType, TPropertyType>(
    this IEnumerable<TType> this, <Property Declaration>)
{
    // Generic version of the above code?
}

Можно ли это сделать?

Ответы [ 2 ]

5 голосов
/ 10 декабря 2010

Action не очень Linq'ish. Как насчет Func вместо этого? (Непроверенный код)

public static IEnumerable<TProp> RecurseSelect<TSource, TProp>(
  this IEnumerable<TSource> source,
  Func<TSource, TProp> propertySelector,
  Func<TSource, IEnumerable<TSource>> childrenSelector
)
{
  foreach(TSource x in source)
  {
    yield return propertySelector(x);
    IEnumerable<TSource> children = childrenSelector(x);
    IEnumerable<TProp> values = children.RecurseSelect(propertySelector, childrenSelector);
    foreach(TProp y in values)
    {
      yield return y;
    }
  }
}

А потом

IEnumerable<Structure> structures = GetStructures();
IEnumerable<int> structureIds = structures.RecurseSelect(
  s => s.StructureId,
  s => s.Children);
1 голос
/ 10 декабря 2010

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

У вас также нет механизма для получения дочерних элементов ваших других классов.(свойство r.Children, которое вы используете).

Двумя вашими решениями будет использование интерфейсов (то есть определите IHasChildren и IGetProperty), которые могут использоваться в качестве базовых типов для простого алгоритма, илиВы можете передать в свой метод функции, которые позволяют более свободно вычислять это.Например, подпись вашего метода может быть такой:

public static IEnumerable<TPropertyType> GetPropertyValues<TType, TPropertyType>
        (this IEnumerable<TType> rootItem, Func<TType, IEnumerable<TType>> getChildren, Func<TType, TPropertyType> getIdValue)

... но это не будет очень красиво!

...