Рекурсивная фильтрация Linq для объектов

можно рекурсивно фильтровать все элементы в рекурсивном дереве с помощью linq для объектов.

Это модель, которую я использую. Это дается мне другим приложением

public class Menu
{
   public string Name{get;set;}
   public string Roles{get;set;}
   public List<Menu> Children{get;set;}
}

Когда пользователь входит в мое приложение, мне нужно проверить роли пользователей против ролей, указанных в пункте меню. Я знаю, что могу написать рекурсивный метод, который проверяет это, используя цикл for.

В любом случае, я получаю это, используя "MenuList.Where(.. проверить роли)

заблаговременно

Ответ 1

Я бы просто реализовал другой метод в классе Menu:

public class Menu
{
    public string Name { get; set; }
    public string Roles { get; set; }
    public List<Menu> Children { get; set; }
    /// <summary>
    /// Checks whether this object or any of its children are in the specified role
    /// </summary>        
    public bool InRole(string role)
    {
        if (role == null)
        {
            throw new ArgumentNullException("role");
        }
        var inRole = (this.Roles ?? String.Empty).Contains(role);
        if (!inRole & Children != null)
        {
            return Children.Any(child => child.InRole(role));
        }
        return inRole;
    }
}

И тогда вы можете просто написать запросы LINQ, например:

var inRole = menuList.Where(menu => menu.InRole("admin"));

Он будет работать рекурсивно.

Ответ 2

Попробуйте этот метод расширения:

public static IEnumerable<T> Flatten<T, R>(this IEnumerable<T> source, Func<T, R> recursion) where R : IEnumerable<T>
{
    return source.SelectMany(x => (recursion(x) != null && recursion(x).Any()) ? recursion(x).Flatten(recursion) : null)
                 .Where(x => x != null);
}

И вы можете использовать его следующим образом:

menu.Flatten(x => x.Children).Where(x => x.Roles.Contains(role));