C# 从树结构的每个级别获取属性

C# 从树结构的每个级别获取属性,c#,.net,generics,C#,.net,Generics,我有一个对象列表,其中列表中的每个对象下面都可能有另一个相同类型的列表,这是一个非常标准的树结构。我正在寻找一种方法,从这个树的每一层通用地提取一个属性,因为我想潜在地将其中的几个属性提取到一个扁平列表中 对象示例: public class Group { public List<Group> SubGroups { get; set; } public List<OtherStuff> OtherStuffs { get; set; } pu

我有一个对象列表,其中列表中的每个对象下面都可能有另一个相同类型的列表,这是一个非常标准的树结构。我正在寻找一种方法,从这个树的每一层通用地提取一个属性,因为我想潜在地将其中的几个属性提取到一个扁平列表中

对象示例:

public class Group {

    public List<Group> SubGroups { get; set; }
    public List<OtherStuff> OtherStuffs { get; set; }
    public OtherThing Thing { get; set; }

}
但仍然能够

groups.FlattenProperty(g => g.OtherStuffs).SelectMany(s => s);
我对数据结构没有太多的控制权,因为它是遗留系统的一部分,所以修改结构实际上不是一个选项


是否有一个合理可重用的现有解决方案?

我相信这就是您所寻找的

public static IEnumerable<T> FlattenProperty<T>(this Group g, Func<Group,T> transform)
{
    yield return transform(g);
    foreach(var item in g.SubGroups.SelectMany(sub => sub.FlattenProperty(transform)))
       yield return item;
}

对朱哈尔的答案稍加修改,允许我最终使用任意对象

public static IEnumerable<TV> FlattenTreeProperty<T, TV>(this IEnumerable<T> collectionToRecurse, Func<T, IEnumerable<T>> childrenSelector, Func<T, TV> propertySelector)
{
    var itemsToRecurse = (collectionToRecurse != null ? collectionToRecurse as IList<T> ?? collectionToRecurse.ToList() : new List<T>());

    if (!itemsToRecurse.Any())
    {
        yield break;
    }

    foreach (var item in itemsToRecurse.Select(propertySelector).Where(i => i != null))
    {
        yield return item;
    }

    foreach (var itemList in itemsToRecurse.Select(childrenSelector).Where(i => i != null))
    {
        foreach (var item in itemList.FlattenTreeProperty(childrenSelector, propertySelector))
        {
            yield return item;
        }
    }
}
它上面的超负荷清理给了我想要的东西

public static IEnumerable<T> FlattenProperty<T>(this Group g, Func<Group,T> transform)
{
    yield return transform(g);
    foreach(var item in g.SubGroups.SelectMany(sub => sub.FlattenProperty(transform)))
       yield return item;
}

编辑:修复了稀疏树,如果任何子项为空,SelectMany会抛出异常

OtherThing是什么?OtherThing是另一个对象,作为组对象的属性。是的,我认为这与我想要的非常接近,谢谢!我修改了您的方法,并添加了一些内容,使其不局限于我的特定对象类型,以便在其他地方重复使用。
public static IEnumerable<TV> FlattenTreeProperty<T, TV>(this IEnumerable<T> collectionToRecurse, Func<T, IEnumerable<T>> childrenSelector, Func<T, TV> propertySelector)
{
    var itemsToRecurse = (collectionToRecurse != null ? collectionToRecurse as IList<T> ?? collectionToRecurse.ToList() : new List<T>());

    if (!itemsToRecurse.Any())
    {
        yield break;
    }

    foreach (var item in itemsToRecurse.Select(propertySelector).Where(i => i != null))
    {
        yield return item;
    }

    foreach (var itemList in itemsToRecurse.Select(childrenSelector).Where(i => i != null))
    {
        foreach (var item in itemList.FlattenTreeProperty(childrenSelector, propertySelector))
        {
            yield return item;
        }
    }
}
groups.FlattenTreeProperty(g => g.SubGroups, g => g.OtherStuffs)