如果改写如下,可以改进所写的语句......
good = m_seedsfilter==0 ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
...但总的来说,您应该熟悉三元语句。最初发布的代码或 xanatos 的版本或我的代码都没有本质上的邪恶。三元语句并不邪恶,它们是语言的基本特征,一旦你熟悉了它们,你会注意到这样的代码(正如我发布的,而不是你原来的帖子中写的)实际上更容易比一连串的 if-else 语句更容易阅读。例如,在这段代码中,您可以简单地阅读以下语句:“变量good等于...如果m_seedsfilter==0,则true,否则,如果m_seedsfilter==1,则newClusters(Sp),否则,@ 987654328@。”
请注意,我上面的版本避免对变量good 进行三个单独的赋值,并清楚地表明该语句的目标是为good 赋值。另外,这样写,它清楚地表明这是一个“switch-case”结构,默认情况是newSeed(Sp)。
应该注意的是,只要operator!() 的m_seedsfilter 类型没有被覆盖,我上面的重写是好的。如果是,那么您必须使用它来保留原始版本的行为...
good = !m_seedsfilter ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
...正如 xanatos 下面的评论所证明的那样,如果您的 newClusters() 和 newSeed() 方法返回的类型彼此不同,并且如果这些类型是用精心设计的无意义转换运算符编写的,那么您将拥有恢复到原始代码本身(尽管希望格式更好,如 xanatos 自己的帖子),以便忠实地复制与原始帖子完全相同的行为。但在现实世界中,没有人会这样做,所以我上面的第一个版本应该没问题。
更新,在原始帖子/答案两年半之后:
有趣的是,@TimothyShields 和我不时地对此表示赞同,而 Tim 的回答似乎始终保持在这个答案的 50% 左右,或多或少(截至本次更新为 43 对 22)。
我想我会添加另一个例子来说明三元语句在明智地使用时可以增加的清晰度。下面的示例是我为调用堆栈使用分析器(一种分析编译的 C 代码的工具,但该工具本身是用 C# 编写的)编写的代码中的简短 sn-ps。所有三种变体都实现了完全相同的目标,至少就外部可见效果而言。
1.没有三元运算符:
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
if (fcnInfo.callDepth == 0)
{
Console.Write(" (leaf function");
}
else if (fcnInfo.callDepth == 1)
{
Console.Write(" (calls 1 level deeper");
}
else
{
Console.Write(" (calls " + fcnInfo.callDepth + " levels deeper");
}
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
2。使用三元运算符,分别调用 Console.Write():
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
Console.Write((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper"));
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
3.使用三元运算符,折叠为对 Console.Write() 的一次调用:
Console.WriteLine(
new string(' ', backtraceIndentLevel) + fcnName +
((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper")) +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
有人可能会争辩说,上面三个示例之间的区别微不足道,既然微不足道,为什么不更喜欢更简单的(第一个)变体呢?一切都是为了简洁;用“尽可能少的词”表达一个想法,以便听众/读者在我到达这个想法的结尾时仍然可以记住这个想法的开始。当我和小孩说话时,我会使用简单、简短的句子,因此需要更多的句子来表达一个想法。当我与能说流利我的语言的成年人交谈时,我会使用更长、更复杂的句子来更简洁地表达想法。
这些示例将单行文本打印到标准输出。虽然它们执行的操作很简单,但应该很容易将它们想象为更大序列的子集。我越能清楚地表达该序列的子集,该序列的更多内容就可以在我的编辑器屏幕上显示。当然,我很容易把这种努力做得太过分,使它更难理解;目标是在通俗易懂和简洁之间找到“sweet spot”。我认为,一旦程序员熟悉了三元语句,理解使用它们的代码就会比理解不使用它们的代码更容易(例如上面的 2 和 3,vs. 1 以上)。
有经验的程序员应该对使用三元语句感到舒服的最后一个原因是避免在进行方法调用时创建不必要的临时变量。作为一个例子,我提出了上述例子的第四个变体,其逻辑被浓缩为对Console.WriteLine()的一次调用;结果是 less 易于理解 和 less 简洁:
4.没有三元运算符,折叠为对 Console.Write() 的单个调用:
string tempStr;
if (fcnInfo.callDepth == 0)
{
tempStr = " (leaf function";
}
else if (fcnInfo.callDepth == 1)
{
tempStr = " (calls 1 level deeper";
}
else
{
tempStr = " (calls " + fcnInfo.callDepth + " levels deeper";
}
Console.WriteLine(new string(' ', backtraceIndentLevel) + fcnName + tempStr +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
在争论“没有必要将逻辑压缩为对Console.WriteLine() 的单个调用”之前,请考虑这只是一个示例:想象一下调用其他一些方法,该方法需要多个参数,所有这些都需要基于其他变量的状态。您可以创建自己的临时对象并使用这些临时对象进行方法调用,或者您可以使用三元运算符并让编译器创建自己的(未命名的)临时对象。我再次认为三元运算符比没有三元运算符可以实现更简洁的和可理解的代码。但要使其易于理解,您必须放弃任何先入为主的观念,即三元运算符是邪恶的。