Итерация по списку, который содержит самоссылающийся список

Допустим, у меня есть следующая модель базы данных: Модель базы данных

В коде это выглядит так:

Категории кнопок

public class ButtonCategory
{
    public ButtonCategory()
    {
        this.Buttons = new HashSet<Button>();
        this.SubCategories = new HashSet<ButtonCategory>();
    }

    [Key]
    public int Id { get; set; }

    [Required]
    public string Description { get; set; }

    public int? ParentCategoryId { get; set; }

    [ForeignKey("ParentCategoryId")]
    public virtual ButtonCategory ParentCategory { get; set; }

    public virtual ICollection<ButtonCategory> SubCategories { get; set; }

    public virtual ICollection<Button> Buttons { get; set; }
}

Кнопки

public class Button
{
    [Key]
    public int Id { get; set; }

    public int? ButtonCategoryId { get; set; }

    [ForeignKey("ButtonCategoryId")]
    public virtual ButtonCategory ButtonCategory { get; set; }
}

Как видите, мои ButtonCategories имеют список ссылок на самих себя.

Возникшая проблема заключается в том, что я хочу преобразовать все ButtonCategories в другой тип, скажем, ButtonCategoriesMock. И я хочу сделать то же самое для всех кнопок в списках. Проблема в том, что я не знаю и не могу сказать, сколько существует подуровней. Возможно, что существует только одна подкатегория, но также и то, что это подкатегория подкатегории подкатегории,... и так далее.

Пример

Как легко преобразовать все элементы ButtonCategory и элементы Button в другой тип?

Заранее спасибо!


person Loetn    schedule 26.07.2013    source источник
comment
Если вы хотите сгладить вывод, попробуйте следующее: stackoverflow.com/questions/1938409/   -  person Greg    schedule 26.07.2013


Ответы (1)


Я не уверен насчет «легко», но для этого вы можете реализовать свои собственные рекурсивные методы расширения:

Однако я считаю, что метод Traverse и выбор могут справиться с вашей ситуацией.

    public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
    {
        foreach (T item in source)
        {
            yield return item;

            IEnumerable<T> seqRecurse = fnRecurse(item);

            if (seqRecurse != null)
            {
                foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
                {
                    yield return itemRecurse;
                }
            }

        }
    }

Фрагмент доступен по адресу: LINQ и рекурсивные функции

Видеть:

person jrbeverly    schedule 26.07.2013