有时我在C#3.5中编写丑陋的if-else语句;我知道一些不同的方法来简化表驱动开发,类层次结构,无限方法等等。 问题在于替代方案仍然比编写传统丑陋的if-else语句的范围更广,因为没有惯例。
嵌套if-else的深度对C#3.5来说是否正常?您期望看到哪些方法而不是嵌套if-else第一个?第二个?
如果我有10个输入参数,每个参数有3个状态,我应该将函数映射到每个参数的每个状态的组合(实际上更少,因为并非所有状态都有效,但有时仍然很多)。我可以将这些状态表示为哈希表键和处理程序(lambda),如果键匹配则将调用它们。
它仍然是表驱动,数据驱动的开发组合。想法和模式匹配。
我正在寻找的是扩展C#这样的脚本编写方法(C#3.5就像编写脚本) http://blogs.msdn.com/ericlippert/archive/2004/02/24/79292.aspx
答案 0 :(得分:8)
好问题。 “条件复杂性”是一种代码气味。 Polymorphism是你的朋友。
条件逻辑在其初期是无辜的,当它易于理解并包含在其中时 几行代码。不幸的是,它很少老化。您实现了几个新功能 突然你的条件逻辑变得复杂和膨胀。 [Joshua Kerevsky:重构模式]
如果要学习使用Guard Clauses,你可以做的最简单的事情就是避免嵌套if。
double getPayAmount() {
if (_isDead) return deadAmount();
if (_isSeparated) return separatedAmount();
if (_isRetired) return retiredAmount();
return normalPayAmount();
};
我发现的另一件事情很简单,它使你的代码自我记录,是Consolidating conditionals。
double disabilityAmount() {
if (isNotEligableForDisability()) return 0;
// compute the disability amount
与条件表达式相关的其他有价值的refactoring技术包括Decompose Conditional,Replace Conditional with Visitor,Specification Pattern和Reverse Conditional。
答案 1 :(得分:4)
简单。拿出if的主体并从中取出一个方法。
这是有效的,因为大多数if语句的格式为:
if (condition):
action()
在其他情况下,更具体地说:
if (condition1):
if (condition2):
action()
简化为:
if (condition1 && condition2):
action()
答案 2 :(得分:4)
有很多旧的“形式主义”试图封装极其复杂的表达式来评估许多可能的独立变量,例如“决策表”:
http://en.wikipedia.org/wiki/Decision_table
但是,如果可能的话,我将加入合唱团,提出明智地使用三元运算符的想法,找出最不可能的条件,如果遇到这些条件,可以通过先排除它们来终止其余的评估,并添加...反过来...试图分解最可能的条件和状态,可以让你继续进行而不测试“边缘”案例。
Miriam(上图)的建议令人着迷,甚至优雅,是“概念艺术”;我实际上是要尝试一下,试图“支持”我的怀疑,它会导致代码更难维护。
我务实的一面说,在没有一个非常具体的代码示例,以及条件及其相互作用的完整描述的情况下,这里没有“一刀切”的答案。
我是“标志设置”的粉丝:这意味着无论何时我的应用程序进入一些不太常见的“模式”或“状态”,我都会设置一个布尔标志(对于类来说甚至可能是静态的):对我而言,这简化了稍后写下复杂的if / then else评估。
最好,比尔
答案 3 :(得分:2)
我是三元运营商的忠实粉丝,被许多人所忽视。根据条件为变量赋值是很好的。像这样
foobarString = (foo == bar) ? "foo equals bar" : "foo does not equal bar";
请尝试this article了解详情。
它不会解决你所有的问题,但它非常经济。
答案 4 :(得分:2)
我知道这不是您正在寻找的答案,但如果没有上下文,您的问题很难回答。问题在于重构这样的事情的方式实际上取决于你的代码,它正在做什么,以及你想要完成什么。如果你说你正在检查这些条件中对象的类型,我们可能会抛出像'use polymorphism'这样的答案,但有时候你实际上只需要一些if语句,有时甚至需要那些语句可以重构成更简单的东西。如果没有代码示例,很难说您所属的类别。
答案 5 :(得分:2)
switch (testValue) { case = 1: // do something break; case = 2: // do something else break; case = 3: // do something more break; case = 4 // do what? break; default: throw new Exception("I didn't do anything"); }
如果您的语句超过3深度,那么您应该将其视为有更好方法的标志。可能像Avirdlg建议的那样,将嵌套的if语句分成1个或多个方法。如果你觉得你完全坚持使用多个if-else语句,那么我会将所有if-else语句包装到一个单独的方法中,这样就不会让其他代码变得丑陋。
答案 6 :(得分:1)
如果整个目的是根据各种条件的状态为某个变量赋值,我使用了一个ternery算子。
如果If Else子句正在执行单独的功能块。并且条件很复杂,通过创建临时布尔变量来保持复杂布尔表达式的真/假值来简化。这些变量应适当命名,以表示复杂表达式计算的商业意义。然后使用If else synatx中的布尔变量而不是复杂的布尔表达式。
答案 7 :(得分:1)
我发现自己有时做的一件事是将return
后面的条件颠倒过来;连续几个这样的测试可以帮助减少if
和else
的嵌套。
答案 8 :(得分:1)
不是C#答案,但您可能希望模式匹配。通过模式匹配,您可以获取多个输入,并对所有输入执行同步匹配。例如(F#):
let x=
match cond1, cond2, name with
| _, _, "Bob" -> 9000 // Bob gets 9000, regardless of cond1 or 2
| false, false, _ -> 0
| true, false, _ -> 1
| false, true, _ -> 2
| true, true, "" -> 0 // Both conds but no name gets 0
| true, true, _ -> 3 // Cond1&2 give 3
您可以表达任何组合来创建匹配(这只是表面划痕)。但是,C#不支持这一点,我怀疑它会很快。同时,有一些尝试在C#中尝试此操作,例如:http://codebetter.com/blogs/matthew.podwysocki/archive/2008/09/16/functional-c-pattern-matching.aspx。谷歌可以出现更多;也许一个人会适合你。
答案 9 :(得分:0)
尝试使用策略或命令等模式
答案 10 :(得分:0)
在简单的情况下,你应该能够解决基本的功能分解问题。对于更复杂的场景,我使用Specification Pattern取得了巨大的成功。