为什么我要重构这段代码,因为循环复杂度是 58
我读到,拥有 CC 10 或更少的代码将是高度可维护的。但我写的方法有CC 58。感谢VS 2010代码分析工具。我相信,就我的理解,我写的方法非常简单、可读、可维护。因此我不喜欢重构代码。但由于 CC 高于可接受的水平,我想知道为什么要重构这种方法。我正在学习一些东西来改进我的代码如果我有错误,请纠正我。这是代码。
private string MapBathRooms(string value)
{
double retValue = 0;
if (value == "1" || value == "One")
retValue = 1;
if (value == "OneAndHalf" || value == "1.5" || value == "1 1/2")
retValue = 1.5;
if (value == "2" || value == "Two")
retValue = 2;
if (value == "TwoAndHalf" || value == "2.5" || value == "2 1/2")
retValue = 2.5;
if (value == "3" || value == "Three")
retValue = 3;
if (value == "ThreeAndHalf" || value == "3.5" || value == "3 1/2")
retValue = 3.5;
if (value == "4" || value == "Four")
retValue = 4;
if (value == "FourAndHalf" || value == "4.5" || value == "4 1/2")
retValue = 4.5;
if (value == "5" || value == "Five" || value == "FourOrMore")
retValue = 5;
if (value == "FiveAndHalf" || value == "5.5" || value == "5 1/2")
retValue = 5.5;
if (value == "6" || value == "Six")
retValue = 6;
if (value == "SixAndHalf" || value == "6.5" || value == "6 1/2")
retValue = 6.5;
if (value == "7" || value == "Seven")
retValue = 7;
if (value == "SevenAndHalf" || value == "7.5" || value == "7 1/2")
retValue = 7.5;
if (value == "8" || value == "8+" || value == "Eight" || value == "SevenOrMore")
retValue = 8;
if (value == "EightAndHalf" || value == "8.5" || value == "8 1/2")
retValue = 8.5;
if (value == "9" || value == "Nine")
retValue = 9;
if (value == "NineAndHalf" || value == "9.5" || value == "9 1/2")
retValue = 9.5;
if(value == "10" || value == "Ten")
retValue = 10;
if (value == "TenAndHalf" || value == "10.5" || value == "10 1/2"
|| value == "10+" || value == "MoreThanTen" || value == "11")
retValue = 10.5;
if (retValue == 0)
return value;
return retValue.ToString();
}
I read that having CC 10 or less would be highly maintainable code. But the method that I wrote have CC 58. Thanks to VS 2010 code analysis tool. I believe that the method I wrote is very simple, readable and maintainable as far as my understanding. Hence I would not prefer refactoring the code. But since CC is higher than acceptable, I am wondering why would one refactor this method. I am learning things to improve my code If I have mistake, plese correct me. Here is the code.
private string MapBathRooms(string value)
{
double retValue = 0;
if (value == "1" || value == "One")
retValue = 1;
if (value == "OneAndHalf" || value == "1.5" || value == "1 1/2")
retValue = 1.5;
if (value == "2" || value == "Two")
retValue = 2;
if (value == "TwoAndHalf" || value == "2.5" || value == "2 1/2")
retValue = 2.5;
if (value == "3" || value == "Three")
retValue = 3;
if (value == "ThreeAndHalf" || value == "3.5" || value == "3 1/2")
retValue = 3.5;
if (value == "4" || value == "Four")
retValue = 4;
if (value == "FourAndHalf" || value == "4.5" || value == "4 1/2")
retValue = 4.5;
if (value == "5" || value == "Five" || value == "FourOrMore")
retValue = 5;
if (value == "FiveAndHalf" || value == "5.5" || value == "5 1/2")
retValue = 5.5;
if (value == "6" || value == "Six")
retValue = 6;
if (value == "SixAndHalf" || value == "6.5" || value == "6 1/2")
retValue = 6.5;
if (value == "7" || value == "Seven")
retValue = 7;
if (value == "SevenAndHalf" || value == "7.5" || value == "7 1/2")
retValue = 7.5;
if (value == "8" || value == "8+" || value == "Eight" || value == "SevenOrMore")
retValue = 8;
if (value == "EightAndHalf" || value == "8.5" || value == "8 1/2")
retValue = 8.5;
if (value == "9" || value == "Nine")
retValue = 9;
if (value == "NineAndHalf" || value == "9.5" || value == "9 1/2")
retValue = 9.5;
if(value == "10" || value == "Ten")
retValue = 10;
if (value == "TenAndHalf" || value == "10.5" || value == "10 1/2"
|| value == "10+" || value == "MoreThanTen" || value == "11")
retValue = 10.5;
if (retValue == 0)
return value;
return retValue.ToString();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
为什么不直接使用
Dictionary
呢?这将使代码变得更加简单 - 您已将数据与查找代码分开。事实上,您可以通过避免 ToString 调用来使其变得更简单 - 只需将其设为
Dictionary
:正如 ChrisF 所说,您还可以从文件或其他资源中读取它。
这样做的好处:
Dictionary<,>.Add
,因此如果您有重复的键,则在初始化类型时会出现异常,因此您会立即发现错误。这么说吧 - 您曾经考虑从基于字典的版本重构为“大量实际代码”版本吗?我当然不会。
如果你真的真的想在方法中拥有所有内容,你总是可以使用 switch 语句:
我自己仍然使用字典形式......但这确实有一个非常小的优势,即重复检测被提前到 < em>编译时。
Why not just have a
Dictionary<string, double>
? That will make for much simpler code - you've separated the data from the lookup code.In fact, you could make it even simpler by avoiding the ToString call - just make it a
Dictionary<string, string>
:As ChrisF says, you could also read this from a file or other resource.
Benefits of doing this:
Dictionary<,>.Add
, if you have a duplicate key you'll get an exception when you initialize the type, so you'll spot the error immediately.Put it this way - would you ever consider refactoring from the Dictionary-based version to the "lots of real code" version? I certainly wouldn't.
If you really, really want to have it all in the method, you could always use a switch statement:
I'd still use the dictionary form myself... but this does have the very slight advantage that duplicate detection is brought forward to compile-time.
我同意其他发帖者关于使用字典进行映射的观点,但我也想指出,这样的代码通常很难发现错误。例如:
用于进行转换的通用算法最初可能更难编写,但从长远来看可以轻松节省您的时间。
I agree with the other posters about using a dictionary for a mapping, but I also want to point out that code like this often has hard to find bugs. For example:
A general algorithm for doing the conversion might be harder to write initially, but could easily save you time in the long run.
回答为什么而不是如何:
一个原因是我在 Jon Skeet 的答案的评论中提到的,但是使用字典和外部资源允许您修改应用程序的行为,而不必在每次需求更改时重建它。
另一个是执行速度。您的代码必须检查几十个字符串才能找到结果 - 虽然有多种方法可以在找到匹配项后停止执行,但您仍然需要检查所有字符串。无论输入如何,使用字典都会为您提供线性访问时间。
To answer the why rather than the how:
One reason is the one I mention in my comment on Jon Skeet's answer, but using the dictionary and external resource allows you to modify the behaviour of your application without having to rebuild it every time the requirements change.
Another is speed of execution. Your code has to check a few dozen strings to find the result - while there are ways to stop the execution once you've found a match, you still have to potentially check them all. Using a dictionary will give you linear access times regardless of the input.
是的。确实非常易于维护。
尝试这样做:
将其保留在字典中应该将 CC 保持为 2。可以通过从文件或其他资源读取字典来初始化字典。
CC(几乎)是方法的潜在执行路径的数量。你对该方法的CC那么高,因为你还没有使用适合处理此类问题的结构(这里:字典)。使用适当的数据结构来解决问题可以保持代码整洁且可重用。
Yeah. Very maintainable indeed.
Try this instead:
Keeping this in dictionary should keep the CC to just 2. The dictionary may be initialized by reading it from file, or another resource.
CC is (pretty much) the number of potential execution paths of a method. Your CC for that method is that high, because you haven't used a structure suitable to deal with this kind of problems (here: a dictionary). Using appropriate data structures to solve problems keeps your code tidy and reusable.
根据 DRY(不要重复)的原则,您可以用
switch
替换所有这些if
语句。该开关将使用哈希表实现,因此它也将比所有if
语句更快。您可以删除捕获数字的数字表示形式的所有情况,因为这是由后备处理的。
我不认为将字符串转换为数字,然后再次转换回字符串有什么意义。使用文字字符串(因为它们是预先创建的)比动态创建字符串更有效。此外,这还消除了区域性问题,例如值
9.5
将生成字符串"9,5"
而不是"9.5"
对于某些文化。请注意,我保留了输入
"11"
的大小写,导致返回值为"10.5"
。我不确定这是否是一个错误,但这就是原始代码的作用。With the principle of DRY (don't repeat yourself) you can replace all those
if
statements with aswitch
. The switch will be implemented using a hash table, so it will also be faster than all theif
statements.You can remove all cases where you catch the numeric representation of the number, as that is handled by the fallback.
I don't see a point in converting the string into a number, and then back to a string again. It's more afficient to use literal strings (as they are pre-created) than creating the string on the fly. Also, that elliminates the culture issue, where for example the value
9.5
would result in the string"9,5"
instead of"9.5"
for some cultures.Note that I left the case of the input
"11"
results in the return value of"10.5"
. I'm not sure if that's a bug, but that's what the original code does.对于您的一般问题,对于无法按照其他响应者针对此特定功能的建议进行重构的其他情况,CC 有一种变体,它将案例陈述视为单个分支,因为它实际上与线性行相同代码易于理解(尽管不适用于测试覆盖率)。许多测量一种变体的工具也会提供另一种变体。我建议使用 case=1 变体,或者与您正在使用的变体一起使用。
To your general question, for other cases that cannot be refactored as suggested by other responders for this specific function, there is a variant of CC that counts a case statement as a single branch on the grounds that it is virtually the same as linear lines of code in ease of comprehension (though not for test coverage). Many tools that measure one variant will offer the other. I suggest using the case=1 variant instead or as well as the one you are using.