使用返回的错误消息确定是否存在错误

时间:2011-06-08 18:43:50

标签: c# return-type

我最近和一个伙伴讨论过返回值只有一个含义。在我之前的工作中,我们使用C ++并使用了typedef'ed wBOOL,因此0为wFALSE,1为wTRUE。建筑师说我们也可以返回2,3,4 ......以获取更多信息,我认为这是一个可怕的想法。如果我们期望wTRUE = 1且wFALSE = 0且wBOOL = {wTRUE,wFALSE},则应该避免返回任何其他内容......现在,转到今天的C#。

我最近审查了一段代码,其中有一系列函数确定是否存在错误并将字符串返回给用户:

private bool IsTestReady(out string errorMessage)
{
  bool isReady = true;
  errorMessage = string.Empty;
  if(FailureCondition1)
  {
    isReady = false;
    errorMessage = FailureMessage1;
  }
  else if(FailureCondition2)
  {
    isReady = false;
    errorMessage = FailureMessage2;
  }
  //... other conditions
  return isReady;
}

然后,使用这些功能...

private enum Tests
{ TestA, TestB, TestC }
private void UpdateUI()
{
  string error = string.Empty;
  bool isTestReady;
  switch(this.runningTest) // which test are we running (TestA, TestB, or TestC)
  {
    case Tests.TestA:
      isTestReady = IsTestAReady(error);
      break;
    case Tests.TestB:
      isTestReady = IsTestBReady(error);
      break;
    case Tests.TestC:
      isTestReady = IsTestCReady(error);
      break;
  }
  runTestButton.Enabled = isTestReady;
  runTestLabel.Text = error;
}

我想把它们分成两种方法:

private string GetTestAErrorMessage()
{
  //same as IsTestReady, but only returns the error string, no boolean stuffs
}

private bool IsTestAReady
{
  get{ return string.IsNullOrEmpty(GetTestAErrorMessage()); }
}

这是否违反了没有返回值的原则意味着多于一件事?例如,在这种情况下,如果出现错误消息IsNullOrEmpty,则没有错误。我认为这不违反那个原则;我的合作呢。对我而言,与此无异:

class Person
{
  public int Height {get;}
  public bool IsTall() { return Height > 10; }
}

对此问题采取不同方法的任何想法或建议?我认为out参数是最差的解决方案。

3 个答案:

答案 0 :(得分:5)

返回值和错误消息在技术上不绑定在一起。您可以让开发人员稍后出现并向IsTestReady添加新的故障条件,并且该故障情况可能不会设置错误消息。或者,也许有消息,但它并不完全代表失败(例如,可能是警告或其他内容),因此错误消息参数可能已设置,但返回值为true。

在这种情况下,异常并不真正起作用,因为StriplingWarrior在他的评论中写的确切原因 - 异常应该用于非正常操作状态,而非就绪测试是正常状态。

一种解决方案可能是删除错误消息参数并让IsTestReady函数返回一个类:

public class TestReadyResult {
    public bool IsReady { get; set; }
    public string Error { get; set; }
}

只有一个要检查的属性 - TestReadyResult.IsReady - 用于测试状态,如果需要,可以将Error属性用于非就绪状态。也没有额外的参数来管理函数调用。

答案 1 :(得分:3)

我不喜欢使用null或null返回值表示没有错。比你给出的更好的比较是:

class Person
{
    public int Height {get;}
    public bool IsBorn() { return Height > 0; }
}

在.NET中,通常的做法是使用您在原始方法中看到的“bool return with out parameter”模式(例如,参见各种TryParse方法)。但是,如果您愿意,另一种解决方案是创建一个TestReadyCheck类,其中包含布尔值和字符串作为属性。我和下面的课做了类似的事情,对此非常满意。

public class RequestFilterResult
{
    public static readonly RequestFilterResult Allow = new RequestFilterResult(true, null);
    public static RequestFilterResult Deny(string reason) { return new RequestFilterResult(false, reason); }
    protected RequestFilterResult(bool allowRequest, string denialReason)
    {
        AllowRequest = allowRequest;
        DenialReason = denialReason;
    }

    public bool AllowRequest { get; private set; }
    public string DenialReason { get; private set; }
}

这允许以下用法:

public RequestFilterResult Filter(...)
{
    if (FailureCondition1) return RequestFilterResult.Deny(FailureMessage1);
    if (FailureCondition2) return RequestFilterResult.Deny(FailureMessage2);
    return RequestFilterResult.Allow();
}

这是简洁的,同时强制执行失败结果会提供失败消息,而成功结果则不会。

在旁注中,switch语句的结构对我来说就像是一种代码味道。您可能想要考虑利用多态的方法。也许让每个测试都有自己的类,上面有IsTestReady方法?

答案 2 :(得分:0)

我会使用异常来传达有关失败状态的信息,而不是依赖调用者知道如何使用错误消息字段(即使它是私有的)。