我读过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();
}
答案 0 :(得分:15)
为什么不只有Dictionary<string, double>
?这将使更多更简单的代码 - 您已将数据与查找代码分开。
private static readonly Dictionary<string, double> BathRoomMap =
new Dictionary<string, double>
{
{ "1", 1 },
{ "One", 1 },
{ "OneAndHalf", 1.5 },
{ "1.5", 1.5 },
{ "1 1/2", 1.5 }
// etc
};
private static string MapBathRooms(string value)
{
double result;
if (!BathRoomMap.TryGetValue(value, out result))
{
return value; // Lookup failed
}
return result.ToString();
}
事实上,你可以通过避免ToString调用使其变得更简单 - 只需将其设为Dictionary<string, string>
:
private static readonly Dictionary<string, string> BathRoomMap =
new Dictionary<string, string>
{
// Note: I've removed situations where we'd return the
// same value anyway... no need to map "1" to "1" etc
{ "One", "1" },
{ "OneAndHalf", "1.5" },
{ "1 1/2", "1.5" }
// etc
};
private static string MapBathRooms(string value)
{
string result;
if (!BathRoomMap.TryGetValue(value, out result))
{
return value; // Lookup failed
}
return result;
}
正如ChrisF所说,您也可以从文件或其他资源中读取此内容。
这样做的好处:
Dictionary<,>.Add
,如果您有重复的密钥,则在初始化类型时会出现异常,因此您将立即发现错误。这样说 - 你会曾考虑从基于字典的版本重构到“大量真实代码”版本吗?我当然不会。
如果你真的想要在方法中使用它,你总是可以使用switch语句:
private static string MapBathRooms(string value)
{
switch (value)
{
case "One":
return "1";
case "OneAndHalf":
case "1 1/2":
return "1.5";
...
default:
return value;
}
}
我自己仍然使用字典表单...但这确实有一个非常小的优点,即重复检测被提前到编译 -time。
答案 1 :(得分:3)
我同意其他关于使用字典进行映射的海报,但我也想指出像这样的代码通常很难找到错误。例如:
进行转换的一般算法最初可能难以编写,但从长远来看可以轻松节省时间。
答案 2 :(得分:0)
呀。确实非常可维护。
请改为尝试:
// initialize this somewhere
IDictionary<string, string> mapping;
private string MapBathRooms(string value)
{
if (mapping.ContainsKey(value))
{
return mapping[value];
}
return value;
}
将此保留在字典中应该将CC保持为2.可以通过从文件或其他资源中读取字典来初始化字典。
CC(几乎)是方法的潜在执行路径的数量。你对该方法的CC很高,因为你没有使用适合处理这类问题的结构(这里是一本字典)。使用适当的数据结构来解决问题可以使代码保持整洁和可重用。
答案 3 :(得分:0)
回答原因而不是如何:
我在评论Jon Skeet的答案时提到了一个原因,但使用字典和外部资源可以修改应用程序的行为,而无需在每次需求更改时重建它。
另一个是执行速度。您的代码必须检查几十个字符串才能找到结果 - 虽然有一些方法可以在找到匹配项后停止执行,但您仍然需要检查它们。无论输入如何,使用字典都可以为您提供线性访问时间。
答案 4 :(得分:0)
根据DRY原则(不要重复),您可以用if
替换所有switch
语句。该交换机将使用哈希表实现,因此它也将比所有if
语句更快。
您可以删除捕获数字的数字表示的所有情况,因为它由回退处理。
我没有看到将字符串转换为数字,然后再返回字符串的要点。使用文字字符串(因为它们是预先创建的)比在运行中创建字符串更有效。此外,这消除了文化问题,例如,对于某些文化,值9.5
将导致字符串"9,5"
而不是"9.5"
。
private string MapBathRooms(string value) {
switch (value) {
case "One": value = "1"; break;
case "OneAndHalf":
case "1 1/2": value = "1.5"; break;
case "Two": value = "2"; break;
case "TwoAndHalf":
case "2 1/2": value = "2.5"; break;
case "Three": value = "3"; break;
case "ThreeAndHalf":
case "3 1/2": value = "3.5"; break;
case "Four": value = "4"; break;
case "FourAndHalf":
case "4 1/2": value = "4.5"; break;
case "Five":
case "FourOrMore": value = "5"; break;
case "FiveAndHalf":
case "5 1/2": value = "5.5"; break;
case "Six": value = "6"; break;
case "SixAndHalf":
case "6 1/2": value = "6.5"; break;
case "Seven": value = "7"; break;
case "SevenAndHalf":
case "7 1/2": value = "7.5"; break;
case "8+":
case "Eight":
case "SevenOrMore": value = "8"; break;
case "EightAndHalf":
case "8 1/2": value = "8.5"; break;
case "Nine": value = "9"; break;
case "NineAndHalf":
case "9 1/2": value = "9.5"; break;
case "Ten": value = "10"; break;
case "TenAndHalf":
case "10 1/2":
case "10+":
case "MoreThanTen":
case "11": value = "10.5"; break;
}
return value;
}
请注意,我将输入"11"
的结果保留为"10.5"
的返回值。我不确定这是不是一个错误,但这就是原始代码的作用。
答案 5 :(得分:0)
对于您的一般问题,对于其他响应者对此特定功能无法重构的其他情况,有一种CC的变体将案例陈述统计为单个分支,理由是它几乎与易于理解的线性代码行(虽然不适用于测试覆盖)。测量一种变体的许多工具将提供另一种。我建议使用case = 1变体,或者使用你正在使用的变体。