0

我知道这个问题在某种程度上是一个品味问题。我承认这不是我不明白的事情,这只是我想听听别人的意见。

我需要编写一个带有两个参数的方法,一个布尔值和一个字符串。布尔值在某种意义上(很快就会很明显)是多余的,但它是该方法必须接受两个参数的规范的一部分,并且如果布尔值具有“错误”值,则必须引发带有特定消息文本的异常. true 当且仅当字符串不为空或为空时,布尔值必须为。

所以这里有一些不同的风格来写(希望如此!)同样的事情。你觉得哪一个最易读,并且符合良好的编码习惯?

// option A: Use two if, repeat throw statement and duplication of message string
public void SomeMethod(bool useName, string name)
{
  if (useName && string.IsNullOrEmpty(name))
    throw new SomeException("...");
  if (!useName && !string.IsNullOrEmpty(name))
    throw new SomeException("...");

  // rest of method
}


// option B: Long expression but using only && and ||
public void SomeMethod(bool useName, string name)
{
  if (useName && string.IsNullOrEmpty(name) || !useName && !string.IsNullOrEmpty(name))
    throw new SomeException("...");

  // rest of method
}


// option C: With == operator between booleans
public void SomeMethod(bool useName, string name)
{
  if (useName == string.IsNullOrEmpty(name))
    throw new SomeException("...");

  // rest of method
}


// option D1: With XOR operator
public void SomeMethod(bool useName, string name)
{
  if (!(useName ^ string.IsNullOrEmpty(name)))
    throw new SomeException("...");

  // rest of method
}


// option D2: With XOR operator
public void SomeMethod(bool useName, string name)
{
  if (useName ^ !string.IsNullOrEmpty(name))
    throw new SomeException("...");

  // rest of method
}

当然,也欢迎您提出其他可能性。消息文本"..."将类似于“如果 'useName' 为真,则必须给出名称,如果 'useName' 为假,则不允许使用名称”。

4

2 回答 2

1

尽管在某些情况下可以使用这些技巧来提高可读性,但在这种情况下,我会说 C、D、E 是糟糕的选择——它们采用两种不同的预期场景并将它们组合成一个条件,这可能会让人难以理解你的意图/混淆读者。这使得代码更难维护和调试(你必须想一想才能理解发生了什么,这增加了你犯错误的风险)。

(我会进一步使用 D 和 E 并说它们也很糟糕,因为它们将二进制算术应用于布尔值,这意味着您依赖于从 bool(真/假)到可以安全的某个整数值的隐式转换异或然后隐式转换回布尔值。我更喜欢避免隐式转换,并小心地将布尔值视为布尔值)

A、B 是更好的选择,因为它们简单而明确地依次说明了它们对每个预期场景的含义。将来维护您的代码的人不太可能对代码在不同条件下的预期行为感到困惑。

但是,这里有几个其他选项可能会使代码更易于阅读:

bool nameIsValid = (!string.IsNullOrEmpty(name));
if (useName)
{
  if (!nameIsValid) 
    throw new SomeException("..."); 
}
else if (nameIsValid) 
{
  throw new SomeException("..."); 
}

(使用else使读者不必重新评估“useName”条件,这可以加快阅读时间)

或者,以更紧凑的方式:

bool nameIsValid = (!string.IsNullOrEmpty(name));
if ((useName && !nameIsValid) || (!useName && nameIsValid))
    throw new SomeException("..."); 

(使用临时变量,您可以压缩/减少代码并使其更具可读性,同时仍明确指定您希望涵盖的两个单独场景)

甚至:

bool nameIsValid = (!string.IsNullOrEmpty(name));

// If we are using a name it MUST be valid
if (useName && !nameIsValid)
    throw new SomeException("..."); 

// If we are NOT using a name, it is illegal to supply one
if (!useName && nameIsValid)
    throw new SomeException("..."); 

注释可用于阐明检查的目的,并允许阅读您的代码的人了解代码的用途,而无需考虑条件表达式的含义。(我的意思是很容易看出它做了什么,但条件!usename && nameIsValid并不能解释我们为什么要检查它。

最后一个例子是我个人的偏好——因为我已经说明了我打算发生什么,为什么我打算这样做,以及实际编写代码来实现它。这允许任何阅读代码的程序员轻松检查我所说的意思。它为您提供了一个简单的交叉检查。(有些人会声称这样做的风险是有人可以在不更新评论的情况下修改代码,这会使评论产生误导 - 但如果快速浏览显示代码和评论似乎彼此不匹配,那么你知道的有问题,值得花时间在该代码上进行修复。如果它们匹配,则快速交叉检查成功,您可以更加确信代码可能符合预期(因此您只需要考虑设计是否正确,而不是实现))。

于 2012-10-08T22:10:08.053 回答
1

如果方法需要知道字符串是空还是空,它可以自己检查它,它不需要强制调用者进行检查,或者冒着调用者(有意或无意)传入错误布尔值的风险价值。首先不需要传递这样的布尔值,因此不需要检查它,因为你知道你不会做错。

话虽如此,我不知道为什么有人不会选择选项 C,如果他们需要比较两个布尔表达式。A 和 B 只是多余的。它是为了添加代码而添加代码。这就像在那里扔无操作一样。D 只是不必要的深奥。当有一个运算符完全符合您的要求operator ==

于 2012-10-08T20:50:34.983 回答