2

我想验证命令行参数并在出现错误时输出错误消息。我的问题是,如果命令行参数的数量增加(目前,我只有3),那么我的代码将变成意大利面代码。我怎样才能减少给定代码的圈复杂度?如何减少这些if else语句的圈复杂度

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"); 

回答

4

我建议提取CommandLine

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; 
    } 
    } 
} 

有这个类写,你可以把

if (!CommandLine.IsValid) { 
    Console.WriteLine("Parameters structure is inconsistent"); 

    return; 
} 

if (CommandLine.Arg1 == "quit") { 
    ... 
} 
+2

正是我在想什么,但为什么你把它全部**静态**? – Maarten

+0

@Maarten:我们对应用程序只有*一个*命令行,所以我们不需要'CommandLine'类的许多实例(像'Application','Environment'和类似的类) –

+1

@DmitryBychenko:这是正确的,但这也会让你的班级更难测试或替换。我可以提出这些简单的改变:** 1。**使类和它的成员非静态** 2。**用'commandLine'字符串参数来扩充ctor,而不是'Environment.GetCommandLineArgs( )',最后** 3。**添加一个静态的'Instance'属性或字段,该属性或字段返回/被初始化为绑定到实际命令行的实例:'public static CommandLine Instance = new CommandLine(Environment.GetCommandLineArgs())'。 – stakx

1

也许最重要的是要观察你的代码是你几次做同样的事情,尽管具有不同的输入"-r"Arg1,"-n"Arg2,"-p"Arg3。也就是说,你下面的代码片段出现3次(减去我重新格式化):

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; 
    } 
} 

现在您更换反复ifelse下列要求:

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"); 
} 
1

这个问题是如何重用代码一个简单的例子。

  • 查找代码似乎已被复制/粘贴,
  • 放在一个功能,
  • 副本之间的任何差异,将它们作为参数,
  • 替换函数调用的副本。

结果是

// 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); 

当然,如果你没有复制/粘贴代码开始就可以避免这一切重写。