【问题标题】:Error Reporting错误报告
【发布时间】:2013-01-21 22:33:49
【问题描述】:

我有一个遵循命令模式的类。 它有 2 个方法,即 Execute 和 CanExecute,用于检查是否调用 Execute(它们派生自 ICommand)。 CanExecute 调用了一些方法来检查所有必需的服务是否正在运行、版本是否正确等。

调用 CanExecute 后,它可能会失败并返回 false,我需要知道原因。是不是因为版本不好、服务、文件丢失等原因?

了解问题所在的最佳策略是什么

一个选项是,每当所需条件失败时,我可以抛出一个异常,该异常将在消息字段中描述错误。然而,它会失败的可能性是预期的和you shouldn't use exceptions for regular flow of control。所以我真的不确定。

谢谢。

【问题讨论】:

  • 好像你想要一个状态机。
  • @AustinSalonen 我正在查找它,但我并没有真正理解你的意思,你能详细说明(如果合适的话可能在答案中)?
  • 肯你能不能提出一个更好的问题,以便有人可以提供适当的答案..?
  • @DJKRAZE 我重新制定了,我希望现在可以了。如果没有,我很抱歉,我需要更多信息为什么。感谢您的关心。
  • UI 是否需要向用户展示 CanExecute() 返回 false 的原因?或者,作为开发人员,您是否只需要出于开发目的的信息?

标签: c# oop design-patterns command-pattern


【解决方案1】:

您可以使用一组“原因”来告诉类的用户为什么 CanExecute 返回 false。原因可以很简单IEnumerable<string>

public bool CanExecute() {
  var messages = new List<string>();

  if (!Condition1) {
    messages.Add("Missing Condition1");
  }

  ...

  Messages = messages;
  return messages.Count == 0;
}

public IEnumerable<string> Messages { get; private set; }

然后,客户端代码可以向最终用户显示消息集合。

更新

您还可以将新的命令与消息相关联,为用户提供解决问题的方法。在这种情况下,您可以创建自己的类来封装该信息,而不是 IEnumerable&lt;string&gt;

public class Message {
  public string Text { get; set; }
  public ICommand Command { get; set; }
}

...

public bool CanExecute() {
  var messages = new List<Message>();

  if (!Condition1) {
    messages.Add(
      new Message { 
        Text = "Missing Condition1", 
        Command = new FixCondition1Command() 
      }
    );
  }

  ...

  Messages = messages;
  return messages.Count == 0;
}

public IEnumerable<Message> Messages { get; private set; }

【讨论】:

  • 我想过,但我想有机会从错误中恢复,如果我使用你的方法,我将不得不通过比较可能不是最好的字符串来做到这一点练习。
  • @Ken:我明白你的意思了。我为此添加了一个想法。
  • 啊,我想到了类似的东西。我想过引发事件并在EventArgs 中有一个 id 对象,以便程序识别问题和一个消息字符串(对于用户),这与您的想法非常相似,但我认为这是一个坏主意,因为事件是不是为那些东西设计的。你介意分享你的意见吗?我真的很感谢你的努力(你不知道),谢谢!
  • @Ken:我不想使用事件,因为从语义上讲,这些条件违规不是“事件”,它们只是来自CanExecute 调用的“返回值”。
  • 哦,我明白你的意思了。好吧,我想我可以使用一个元组。非常感谢!
【解决方案2】:

更新:根据反馈重新设计。

由于 UI 需要 CanExecute() 返回 false 的原因,我想到了两件事:

选项 1: 向命令界面添加一个可枚举的消息属性,并在调用 CanExecute() 期间根据需要填充它。然后 UI 可以根据需要询问该属性。如果你走这条路,请确保在每次调用 CanExecute() 时清除属性的内容,以免丢失状态。

public interface ICommand
{
    IEnumerable<string> Messages { get; }
    bool CanExecute();
    void Execute();
}

public class SomeCommand : ICommand
{
    public IEnumerable<string> Messages { get; private set; }

    public bool CanExecute()
    {
        var messages = new List<string>();

        var canExecute = true;

        if (SomeCondition)
        {
            canExecute = false;
            messages.Add("Some reason");
        }

        if (AnotherCondition)
        {
            canExecute = false;
            messages.Add("Another reason");
        }

        Messages = messages;

        return canExecute;
    }

    public void Execute() { }
}

选项 2: 让 CanExecute() 返回一个包含布尔值以及可枚举消息属性的对象。这表明消息仅适用于 CanExecute() 的调用。但是,根据您实施的位置/方式(例如数据绑定),这可能会使其他场景复杂化,超出您的预期。

public class CanExecuteResult
{
    public bool CanExecute { get; set; }
    public IEnumerable<string> Messages { get; set; }
}

public interface ICommand
{
    CanExecuteResult CanExecute();
    void Execute();
}

public class SomeCommand : ICommand
{
    public CanExecuteResult CanExecute()
    {
        var result = new CanExecuteResult { CanExecute = true };
        var messages = new List<string>();

        if (SomeCondition)
        {
            result.CanExecute = false;
            messages.Add("Some reason");
        }

        if (AnotherCondition)
        {
            result.CanExecute = false;
            messages.Add("Another reason");
        }

        result.Messages = messages;

        return result;
    }

    public void Execute() { }
}

显然,您希望如何处理接口、可枚举类型等的细节取决于您自己。代码只是想法的一种表示。

【讨论】:

  • 该命令位于 UI 使用的库中。我不能让库依赖于 UI,我也不想像你描述的那样对它进行硬编码。
  • 在我的示例中,ConditionA 和 ConditionB 是您用来确定 CanExecute() 的返回值的任何方法的任意表示。显然,除了您需要记录/呈现的任何信息之外,您还必须编写自己的代码来确定该值是否为真/假。
  • 我不确定你是否真的明白,这可能是我的错,所以让我再试一次。命令类,也是检查所有内容的类,位于一个库程序集中。 GUI 在另一个程序集中。现在例如,如果CanExecute 由于驱动程序暂停而返回 false,我想告诉用户,并询问他是否希望应用程序自动启动它。 (而且因为它在一个库中,另一个 GUI 程序集可能需要不同的操作,所以我不能在库中硬编码任何东西,这是我的困境)。
【解决方案3】:
    Bool CanExecute()
    {
     if(!CheckXXX)
      throw new Exception("CheckXXX function throws an exception")

     if(!CheckYYY)
      throw new Exception("CheckYYY function throws an exception")

    if(!CheckZZZ)
     throw new Exception("CheckZZZ function throws an exception")

    return true; //everything is working fine    
}

【讨论】:

  • 重温最后一段。
猜你喜欢
  • 1970-01-01
  • 2011-08-08
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多