【问题标题】:Replace single node in c# tree替换 c# 树中的单个节点
【发布时间】:2017-07-10 12:32:49
【问题描述】:

我的应用程序中有一个树结构,其中包含用户的分层数据。

public class User {
     //a lot of properties here like Id, Name, Last Name, etc.
     public IEnumerable<User> Employees {get;set;}
}

现在我需要用新项目替换此树中的某些记录。

var changedUsers = GetChangedUsers();
// Replace all changed user fields in original hierarchy 
// (only FirstName, LastName, etc. without touching Employees field)

有没有优雅的方法来实现这一点?

编辑:

我尝试使用递归循环,但更新记录时卡住了。

private void ReplaceUserInHierarchy(User modifiedUser, List<User> users)
        {
            foreach (var user in users)
            {
                if (user.Id == modifiedUser.Id)
                {
                    //we should update here somehow
                    return;
                }

                ReplaceUserInHierarchy(modifiedUser, user.Employees);
            }
        }

【问题讨论】:

  • 需要什么程度的优雅?扁平化层次结构和编辑每个匹配的用户是否足够优雅?
  • 这是讽刺吗?
  • @Gab 扁平化层次结构并加入changedUsers
  • @Gab 完全正确。您的问题缺少主要部分 - 显示您尝试解决此任务的代码以及您无法解决的问题描述(错误或不正确的结果)
  • @tchelidze - 我们该怎么做?

标签: c# .net tree tree-traversal


【解决方案1】:

只需更新匹配给定 id 的用户:

private void ReplaceUserInHierarchy(User modifiedUser, List<User> users)
{
    foreach (var user in users)
    {
        if (user.Id == modifiedUser.Id)
        {
            // update properties of user here
            user.FirstName = modifiedUser.FirstName;
            // etc
            return; // if user can be duplicated in hierarchy, then use continue here
        }

        // assume user cannot be in own employees hierarchy
        ReplaceUserInHierarchy(modifiedUser, user.Employees);
    }
}

提高优雅 - 您可以使用扩展方法来扁平化层次结构。然后搜索您应该更新的用户将如下所示:

var user = users.Flatten(u => u.Employees).FirstOrDefault(u => u.Id == modifiedUser.Id);
if (user != null) // you can throw if user not found
    user.FirstName = modifiedUser.FirstName; // etc        

扁平化可以做为

public static IEnumerable<T> Flatten<T>(
   this IEnumerable<T> source,
   Func<T, IEnumerable<T>> selector)
{
   // null-check arguments
   foreach(var item in source)
   {
       yield return item;
       foreach(var child in Flatten(selector(item), selector))
           yield return child;
   }   
}

进一步改进 - 您可以将扁平层次结构保存到字典中并使用它来更新多个用户:

var usersById = users.Flatten(u => u.Employees).ToDictionary(u => u.Id);
foreach(var modifiedUser in modifiedUsers)
{
    User user;
    if (!usersById.TryGetValue(modifiedUser.Id, out user);)
       continue; // or throw

    user.FirstName = modifiedUser.FirstName; // etc  
}

进一步改进 - 您可以使用 AutoMapper 等库来自动进行映射。

【讨论】:

  • 有没有办法可以替换除雇员以外的所有属性? (大约有 30 个属性)
  • 请注意GetChangedUsers(); 中的最后一个s,您的代码仅适用于一个。
  • @Gab - 听起来你需要看看 AutoMapper 或类似的东西。
  • @HenkHolterman 我的代码更改了 ID 为 modifiedUser 的用户的所有引用s
  • 我仍然认为我需要使用“返回”而不是“继续” - 层次结构中只能有一个具有指定 ID 的用户。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-27
  • 2017-12-29
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多