Вот как я это решил.
Мне нужно иметь 2 класса:
1) LinqToObjectsExtensionMethods
:
using System;
using System.Collections.Generic;
using System.Linq;
namespace APTClient.Model
{
static class LinqToObjectsExtensionMethods
{
private static IEnumerable<HierarchyNode<TEntity>> CreateHierarchy<TEntity, TProperty>(IEnumerable<TEntity> allItems, TEntity parentItem, Func<TEntity, TProperty> idProperty,
Func<TEntity, TProperty> parentIdProperty, object rootItemId, int maxDepth, int depth)
where TEntity : class
{
IEnumerable<TEntity> childs;
if (rootItemId != null)
{
childs = allItems.Where(i => idProperty(i).Equals(rootItemId));
}
else
{
if (parentItem == null)
{
childs = allItems.Where(i => parentIdProperty(i).Equals(default(TProperty)));
}
else
{
childs = allItems.Where(i => parentIdProperty(i).Equals(idProperty(parentItem)));
}
}
if (childs.Count() > 0)
{
depth++;
if ((depth <= maxDepth) || (maxDepth == 0))
{
foreach (var item in childs)
yield return
new HierarchyNode<TEntity>()
{
Entity = item,
ChildNodes =
CreateHierarchy(allItems.AsEnumerable(), item, idProperty, parentIdProperty, null, maxDepth, depth),
Depth = depth,
Parent = parentItem
};
}
}
}
/// <summary>
/// LINQ to Objects (IEnumerable) AsHierachy() extension method
/// </summary>
/// <typeparam name="TEntity">Entity class</typeparam>
/// <typeparam name="TProperty">Property of entity class</typeparam>
/// <param name="allItems">Flat collection of entities</param>
/// <param name="idProperty">Func delegete to Id/Key of entity</param>
/// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
/// <returns>Hierarchical structure of entities</returns>
public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
, Func<TEntity, TProperty> parentIdProperty) where TEntity : class
{
return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, null, 0, 0);
}
/// <summary>
/// LINQ to Objects (IEnumerable) AsHierachy() extension method
/// </summary>
/// <typeparam name="TEntity">Entity class</typeparam>
/// <typeparam name="TProperty">Property of entity class</typeparam>
/// <param name="allItems">Flat collection of entities</param>
/// <param name="idProperty">Func delegete to Id/Key of entity</param>
/// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
/// <param name="rootItemId">Value of root item Id/Key</param>
/// <returns>Hierarchical structure of entities</returns>
public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
, Func<TEntity, TProperty> parentIdProperty, object rootItemId) where TEntity : class
{
return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, rootItemId, 0, 0);
}
/// <summary>
/// LINQ to Objects (IEnumerable) AsHierachy() extension method
/// </summary>
/// <typeparam name="TEntity">Entity class</typeparam>
/// <typeparam name="TProperty">Property of entity class</typeparam>
/// <param name="allItems">Flat collection of entities</param>
/// <param name="idProperty">Func delegete to Id/Key of entity</param>
/// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
/// <param name="rootItemId">Value of root item Id/Key</param>
/// <param name="maxDepth">Maximum depth of tree</param>
/// <returns>Hierarchical structure of entities</returns>
public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
, Func<TEntity, TProperty> parentIdProperty, object rootItemId, int maxDepth) where TEntity : class
{
return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, rootItemId, maxDepth, 0);
}
}}
2) HierarchyNode<T>
:
using System.Collections.Generic;
namespace APTClient.Model
{
public class HierarchyNode<T> where T : class
{
public T Entity { get; set; }
public IEnumerable<HierarchyNode<T>> ChildNodes { get; set; }
public int Depth { get; set; }
public T Parent { get; set; }
}
}
У меня есть List<MyItem> myItemList;
List<MyItem> myItemList = new List<MyItem>();
myItemList.Add(new MyItem(1, "Item1", null));
myItemList.Add(new MyItem(2, "Item1", 1));
myItemList.Add(new MyItem(3, "Item1", 1));
myItemList.Add(new MyItem(4, "Item1", 5));
myItemList.Add(new MyItem(5, "Item1", null));
myItemList.Add(new MyItem(6, "Item1", 3));
myItemList.Add(new MyItem(7, "Item1", null));
Тогда
List<HierarchyNode<MyItem>> = myItemList.AsHierarchy(m => m.ID, m => m.ParentID);