【问题标题】:Modifying a class in a collection with undo使用 undo 修改集合中的类
【发布时间】:2013-03-17 12:31:27
【问题描述】:

这不是关于如何做某事的问题,而是我如何更好地实施某事或以不同的方式思考问题。

我有一个允许用户在网格中选择多行的 winforms 应用程序。这些行代表帐户,当用户选择帐户并点击按钮时,对象上的布尔属性将更改为所选值,无论其现有状态如何。但是,如果验证方法失败,则会向用户发送一条消息,并且需要将布尔属性设置回其原始状态。

public void ModifyAccounts(List<DemoAccount> accts, bool updateIsSpecial)
{
    // Dictionary that will hold the account ID along with the booleans original state
    Dictionary<int, bool> originalState = new Dictionary<int, bool>();
    foreach(var acct in accts)
    {
        // Add the current state to the dictionary
        originalState.Add(acct.Id, acct.IsSpecial);

        acct.IsSpecial = updateIsSpecial;
    }

    // Send the list to another method that loops through each account and checks
    // for specific validation rules. Returns a collection of tuples. The tuple
    // contains the account for item1 and a bool validated flag for item2
    var valAccounts = ValidateAccounts(accts);

    var failedAccounts = from obj in valAccounts
                         where !acct.Item2
                         select new
                                  {
                                      account = obj.Item1,
                                      isValid = obj.Item2
                                  };

    if (failedAccounts.Count() > 0)
    {
        // Alert the user with custom msg box method that the accounts failed
        // Do Custom Method

        // Reset the values of the failed accounts to their previous state. 
        // It is possible that some accounts passed validation and were saved,
        // only the failed accounts should be reset. 
        foreach (var obj in failedAccounts)
        {
            bool originalFlagState = false;
            originalFlagStates.TryGetValue(obj.account.Id, out originalFlagState);
            var origAccount = accts.Where(x => x.Id == obj.account.Id).FirstOrDefault();
            origAccount.IsSpecial = originalFlagState;

        }
    }
}

我希望这不会太令人困惑。我只有大约 3 年的开发经验,这并不多。但是,我觉得在做某事时,如果感觉有更好的方法,那么我可能没有正确或有效地做这件事就足够了。修改帐户标志会更改帐户列表中的对象。显然,将对象添加到新列表只会创建对该对象的引用。所以我不能做一些事情,比如持有 2 个集合,一个用于修改,另一个用于原始状态。我也无法进行深拷贝,因为帐户类未标记为可序列化。由于对象的类型,我无法更改此设置。

感谢任何可以提供建议或见解的人!

【问题讨论】:

  • 您可以在更改状态之前进行验证吗?任何未通过验证的内容都将保持不变。
  • 验证会包含我的更改帐户列表,以查看更改是否可以接受。可以对帐户进行许多更改,因此此方法仅循环通过帐户并检查所有属性并在出现故障时抛出无效标志。所以在修改账户的时候,初始不变的数据基本上已经验证过了。当我将列表发送到验证方法时,我必须将标志设置为用户更改的内容,这现在设置包含该类的任何其他集合。
  • 我个人会想办法预先验证数据。您正在让不良数据进入,这很糟糕(即使您只保留了片刻)。如果您有多个线程,则很容易出现数据损坏问题,并且在维护代码时,您将更有可能破坏某些东西。
  • 这就是我试图找到的最佳方法。

标签: c# collections undo


【解决方案1】:

我不明白您为什么要在更改后而不是事先进行验证。 但是,如果您真的必须在之后验证并使用 undo,那么有一种设计模式支持这种行为

看看命令模式。这是一个代码项目链接,描述了如何实现它 http://www.codeproject.com/Articles/8303/Using-the-Command-pattern-for-undo-functionality

在您的特定情况下,我将遍历命令堆栈并撤消在失败帐户上使用的所有命令

它可能看起来像这样

    foreach (var obj in failedAccounts)
         foreach ICommand command in commandStack
              If(command.element.Equals(obj))
                   command.undo;

command.element 应该包含你想用你的命令改变的元素。

如果你不想要两个 foreach 你可以使用 System.Linq 操作

【讨论】:

    猜你喜欢
    • 2015-04-11
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 2013-05-14
    • 2022-01-01
    • 2019-08-26
    相关资源
    最近更新 更多