如何降低这些 if else 语句的圈复杂度
How to reduce cyclomatic complexity for these if else statements
我正在尝试验证命令行参数并在出现错误时打印错误消息。
我的问题是,如果增加命令行参数的数量(目前,我只有 3 个),那么我的代码就会变成意大利面条代码。如何降低给定代码的圈复杂度?
var isCmdLineWrong = false;
var Arg1 = "Undefined";
var Arg2 = "Undefined";
var Arg3 = "Undefined";
var commandArguments = Environment.GetCommandLineArgs();
if (commandArguments.Contains("-r") && arguments[commandArguments.IndexOf("-r") + 1].StartsWith("-") == false)
Arg1 = commandArguments[commandArguments.IndexOf("-r") + 1];
else
{
isCmdLineWrong = true;
}
if (commandArguments.Contains("-n") && commandArguments[commandArguments.IndexOf("-n") + 1].StartsWith("-") == false)
Arg2 = commandArguments[commandArguments.IndexOf("-n") + 1];
else
{
isCmdLineWrong = true;
}
if (commandArguments.Contains("-p") && commandArguments[commandArguments.IndexOf("-p") + 1].StartsWith("-") == false)
Arg3 = commandArguments[commandArguments.IndexOf("-p") + 1];
else
{
isCmdLineWrong = true;
}
if (isCmdLineWrong) Console.WriteLine("Parameters structure is inconsistent");
我建议提取 CommandLine
class:
public static class CommandLine {
private static String FindValue(string value) {
var commandArguments = Environment.GetCommandLineArgs();
int index = commandArguments.IndexOf(value);
if (index < 0)
return null;
else if (index >= commandArguments.Length - 1)
return null; // cmd like "myRoutine.exe -p"
else
return commandArguments[index + 1];
}
static CommandLine() {
Arg1 = FindValue("-r");
Arg2 = FindValue("-n");
Arg3 = FindValue("-p");
}
public static String Arg1 { get; private set; }
public static String Arg2 { get; private set; }
public static String Arg3 { get; private set; }
public static bool IsValid {
get {
return Arg1 != null && Arg2 != null && Arg3 != null;
}
}
}
写完这个class你可以把
if (!CommandLine.IsValid) {
Console.WriteLine("Parameters structure is inconsistent");
return;
}
if (CommandLine.Arg1 == "quit") {
...
}
可能在您的代码中观察到的最重要的事情是 您多次执行完全相同的事情,尽管输入 "-r"
和 [=14] =]、"-n"
和 Arg2
、"-p"
和 Arg3
。也就是说,您有以下代码片段出现了三次(减去我的重新格式化):
if (commandArguments.Contains(…) &&
arguments[commandArguments.IndexOf(…) + 1].StartsWith("-") == false)
{
… = commandArguments[commandArguments.IndexOf(…) + 1];
}
else
{
isCmdLineWrong = true;
}
Don't Repeat Yourself (DRY) principle 试图警告我们不要编写复制粘贴式的重复代码,而您的原始代码明显违反了它。
我建议您提取公共代码并将其放在单独的方法中。例如:
static bool TryGetArg(string commandArguments, string name, out string value)
{
// Debug.Assert(name.StartsWith("-"));
if (commandArguments.Contains("-") &&
arguments[commandArguments.IndexOf(name) + 1].StartsWith("-") == false)
{
value = commandArguments[commandArguments.IndexOf(name) + 1];
return true;
}
else
{
value = null;
return false;
}
}
现在您将重复的 if
else
替换为以下内容:
string commandArguments = Environment.GetCommandLineArgs();
string arg1 = null;
string arg2 = null;
string arg3 = null;
bool isCmdLineOk = TryGetArg(commandArguments, "-r", out arg1) &&
TryGetArg(commandArguments, "-n", out arg2) &&
TryGetArg(commandArguments, "-p", out arg3);
if (isCmdLineOk)
{
// do something with `arg1`, `arg2`, `arg3`.
}
else
{
// not all of `arg1`, `arg2`, `arg3` could be set to a value.
Console.WriteLine("Parameters structure is inconsistent");
}
这个问题是如何重用代码的一个简单示例。
- 查找似乎是 copied/pasted、
的代码
- 放在一个函数里,
- 副本之间的任何差异,将它们作为参数传递,
- 用函数调用替换副本。
结果是
// Returns this option's value from args, or null on error
public string OptionValue(string[] args, string option)
{
try
{
if (args.Contains(option))
{
string value = args[args.IndexOf(option) + 1]; // reuse expressions as well
if (!value.StartsWith("-"))
return value;
}
return null; // null meaning "undefined"
}
catch
{
return null;
}
}
// And now your code
string[] args = Environment.GetCommandLineArgs();
string Arg1 = OptionValue(args, "-r");
string Arg2 = OptionValue(args, "-n");
string Arg3 = OptionValue(args, "-p");
bool isCmdLineWrong = (Arg1 == null ||
Arg2 == null ||
Arg3 == null);
当然,如果您没有 copy/paste 代码作为开始,那么所有这些重写都是可以避免的。
我正在尝试验证命令行参数并在出现错误时打印错误消息。
我的问题是,如果增加命令行参数的数量(目前,我只有 3 个),那么我的代码就会变成意大利面条代码。如何降低给定代码的圈复杂度?
var isCmdLineWrong = false;
var Arg1 = "Undefined";
var Arg2 = "Undefined";
var Arg3 = "Undefined";
var commandArguments = Environment.GetCommandLineArgs();
if (commandArguments.Contains("-r") && arguments[commandArguments.IndexOf("-r") + 1].StartsWith("-") == false)
Arg1 = commandArguments[commandArguments.IndexOf("-r") + 1];
else
{
isCmdLineWrong = true;
}
if (commandArguments.Contains("-n") && commandArguments[commandArguments.IndexOf("-n") + 1].StartsWith("-") == false)
Arg2 = commandArguments[commandArguments.IndexOf("-n") + 1];
else
{
isCmdLineWrong = true;
}
if (commandArguments.Contains("-p") && commandArguments[commandArguments.IndexOf("-p") + 1].StartsWith("-") == false)
Arg3 = commandArguments[commandArguments.IndexOf("-p") + 1];
else
{
isCmdLineWrong = true;
}
if (isCmdLineWrong) Console.WriteLine("Parameters structure is inconsistent");
我建议提取 CommandLine
class:
public static class CommandLine {
private static String FindValue(string value) {
var commandArguments = Environment.GetCommandLineArgs();
int index = commandArguments.IndexOf(value);
if (index < 0)
return null;
else if (index >= commandArguments.Length - 1)
return null; // cmd like "myRoutine.exe -p"
else
return commandArguments[index + 1];
}
static CommandLine() {
Arg1 = FindValue("-r");
Arg2 = FindValue("-n");
Arg3 = FindValue("-p");
}
public static String Arg1 { get; private set; }
public static String Arg2 { get; private set; }
public static String Arg3 { get; private set; }
public static bool IsValid {
get {
return Arg1 != null && Arg2 != null && Arg3 != null;
}
}
}
写完这个class你可以把
if (!CommandLine.IsValid) {
Console.WriteLine("Parameters structure is inconsistent");
return;
}
if (CommandLine.Arg1 == "quit") {
...
}
可能在您的代码中观察到的最重要的事情是 您多次执行完全相同的事情,尽管输入 "-r"
和 [=14] =]、"-n"
和 Arg2
、"-p"
和 Arg3
。也就是说,您有以下代码片段出现了三次(减去我的重新格式化):
if (commandArguments.Contains(…) &&
arguments[commandArguments.IndexOf(…) + 1].StartsWith("-") == false)
{
… = commandArguments[commandArguments.IndexOf(…) + 1];
}
else
{
isCmdLineWrong = true;
}
Don't Repeat Yourself (DRY) principle 试图警告我们不要编写复制粘贴式的重复代码,而您的原始代码明显违反了它。
我建议您提取公共代码并将其放在单独的方法中。例如:
static bool TryGetArg(string commandArguments, string name, out string value)
{
// Debug.Assert(name.StartsWith("-"));
if (commandArguments.Contains("-") &&
arguments[commandArguments.IndexOf(name) + 1].StartsWith("-") == false)
{
value = commandArguments[commandArguments.IndexOf(name) + 1];
return true;
}
else
{
value = null;
return false;
}
}
现在您将重复的 if
else
替换为以下内容:
string commandArguments = Environment.GetCommandLineArgs();
string arg1 = null;
string arg2 = null;
string arg3 = null;
bool isCmdLineOk = TryGetArg(commandArguments, "-r", out arg1) &&
TryGetArg(commandArguments, "-n", out arg2) &&
TryGetArg(commandArguments, "-p", out arg3);
if (isCmdLineOk)
{
// do something with `arg1`, `arg2`, `arg3`.
}
else
{
// not all of `arg1`, `arg2`, `arg3` could be set to a value.
Console.WriteLine("Parameters structure is inconsistent");
}
这个问题是如何重用代码的一个简单示例。
- 查找似乎是 copied/pasted、 的代码
- 放在一个函数里,
- 副本之间的任何差异,将它们作为参数传递,
- 用函数调用替换副本。
结果是
// Returns this option's value from args, or null on error
public string OptionValue(string[] args, string option)
{
try
{
if (args.Contains(option))
{
string value = args[args.IndexOf(option) + 1]; // reuse expressions as well
if (!value.StartsWith("-"))
return value;
}
return null; // null meaning "undefined"
}
catch
{
return null;
}
}
// And now your code
string[] args = Environment.GetCommandLineArgs();
string Arg1 = OptionValue(args, "-r");
string Arg2 = OptionValue(args, "-n");
string Arg3 = OptionValue(args, "-p");
bool isCmdLineWrong = (Arg1 == null ||
Arg2 == null ||
Arg3 == null);
当然,如果您没有 copy/paste 代码作为开始,那么所有这些重写都是可以避免的。