C# 从平面列表创建递归对象
我有一份清单,如下所示:C# 从平面列表创建递归对象,c#,json,dictionary,serialization,C#,Json,Dictionary,Serialization,我有一份清单,如下所示: List<MenuItem> menuItems = new List<MenuItem>(); menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 }); menuItems.Add(new MenuItem() { SiteMenuId
List<MenuItem> menuItems = new List<MenuItem>();
menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 });
如果答案是肯定的,我怎么做呢?您可以尝试创建这样的类
public class MenuItemTr
{
public MenuItemTr
{
this.MenuItems= new List <MenuItem>
}
public int SiteMenuId {get; set;}
public int ParentId {get; set;}
public string MenuName {get; set;}
public string Url {get; set;}
public int SiteId {get; set;}
public List <MenuItemTr> MenuItems {get; set;}
}
并使用此线程中的解决方案
公共静态IEnumerable GenerateTree(
这是数不清的收藏,
函数id_选择器,
Func父项id选择器,
K root_id=默认值(K))
{
foreach(集合中的var c.Where(c=>parent\u id\u selector(c).Equals(root\u id)))
{
收益回报新树
{
项目=c,
Children=collection.GenerateTree(id_选择器、父id_选择器、id_选择器(c))
};
}
}
}
<代码> > p>您可以考虑使用.< /p>
Json.NET将任何对象序列化为-但转换为字典
则序列化会有问题,因为.NET字典是,并且在序列化为Json时,您(可能)希望保留菜单项
对象的相对顺序。因此,使用Json.NET手动转换为对象树是有意义的,因为Json.NET保留了对象属性的顺序
因此,你会这样做:
public static string CreateJsonFromMenuItems(IList<MenuItem> menuItems)
{
return new JObject
(
menuItems.ToTree(
m => (int?)m.SiteMenuId,
m => m.ParentId, m => new JProperty(m.MenuName, m.Url),
(parent, child) =>
{
if (parent.Value == null || parent.Value.Type == JTokenType.Null)
parent.Value = new JObject();
else if (parent.Value.Type != JTokenType.Object)
throw new InvalidOperationException("MenuItem has both URL and children");
child.MoveTo((JObject)parent.Value);
})
).ToString();
}
正在工作。但此对象将不会像问题中所预期的那样序列化?我需要将json转换为问题中所解释的相同格式。通过序列化MenuItemTr对象,您将拥有json中的MenuItems:[]部分。也许您可以提供一些示例代码,并将您的问题重新表述为“这是我尝试的,为什么它不起作用?”。这是一个“给我代码”的问题,不太适合堆栈溢出。@PaulHicks你读过这个问题的答案了吗?你知道这类问题有一个通用的答案,但如果你阅读我的评论,你会发现这不是我的期望。无论如何,谢谢你的努力,写了这样一篇有帮助的评论。是的,有一些非常适合教程网站,雅虎!答案和其他地方。此网站更喜欢。谢谢你的回答!
var MenuItem = menuItems.GenerateTree(c => c.SiteMenuId, c => c.ParentId);
public static IEnumerable<TreeItem<T>> GenerateTree<T, K>(
this IEnumerable<T> collection,
Func<T, K> id_selector,
Func<T, K> parent_id_selector,
K root_id = default(K))
{
foreach (var c in collection.Where(c => parent_id_selector(c).Equals(root_id)))
{
yield return new TreeItem<T>
{
Item = c,
Children = collection.GenerateTree(id_selector, parent_id_selector, id_selector(c))
};
}
}
}
public static string CreateJsonFromMenuItems(IList<MenuItem> menuItems)
{
return new JObject
(
menuItems.ToTree(
m => (int?)m.SiteMenuId,
m => m.ParentId, m => new JProperty(m.MenuName, m.Url),
(parent, child) =>
{
if (parent.Value == null || parent.Value.Type == JTokenType.Null)
parent.Value = new JObject();
else if (parent.Value.Type != JTokenType.Object)
throw new InvalidOperationException("MenuItem has both URL and children");
child.MoveTo((JObject)parent.Value);
})
).ToString();
}
public static class JsonExtensions
{
public static void MoveTo(this JToken token, JObject newParent)
{
if (newParent == null)
throw new ArgumentNullException();
var toMove = token.AncestorsAndSelf().OfType<JProperty>().First(); // Throws an exception if no parent property found.
if (toMove.Parent != null)
toMove.Remove();
newParent.Add(toMove);
}
}
public static class RecursiveEnumerableExtensions
{
static bool ContainsNonNullKey<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
if (dictionary == null)
throw new ArgumentNullException();
return key == null ? false : dictionary.ContainsKey(key); // Dictionary<int?, X> throws on ContainsKey(null)
}
public static IEnumerable<TResult> ToTree<TInput, TKey, TResult>(
this IEnumerable<TInput> collection,
Func<TInput, TKey> idSelector,
Func<TInput, TKey> parentIdSelector,
Func<TInput, TResult> nodeSelector,
Action<TResult, TResult> addMethod)
{
if (collection == null || idSelector == null || parentIdSelector == null || nodeSelector == null || addMethod == null)
throw new ArgumentNullException();
var list = collection.ToList(); // Prevent multiple enumerations of the incoming enumerable.
var dict = list.ToDictionary(i => idSelector(i), i => nodeSelector(i));
foreach (var input in list.Where(i => dict.ContainsNonNullKey(parentIdSelector(i))))
{
addMethod(dict[parentIdSelector(input)], dict[idSelector(input)]);
}
return list.Where(i => !dict.ContainsNonNullKey(parentIdSelector(i))).Select(i => dict[idSelector(i)]);
}
}