C# 检查数组的值,转到现有值的位置

C# Check Array for values, go to position of existing value

我有一个(希望如此)简单的 C# 问题。

我正在从命令行读取文件的程序中解析参数,我允许短参数和长参数作为输入(所以对于我的场景 /f 和 file 都有效)

以上任一参数后的值应为要读取的文件名。

我想做的是根据选择的参数在数组中找到这个文件名并将其复制到字符串中而不留下任何漏洞。

我有可用的代码,但我不确定它是否"efficient"(并且安全)。

代码(删除评论和写入):

if ( args.Contains("/f") || args.Contains("file"))
{
    int pos = Array.IndexOf(args, "/f");

    if (pos == -1)
        pos = Array.IndexOf(args, "file");

    if (pos > -1)
        pos++;

    inputFile = (args[pos]);

    if (File.Exists(inputFile) == false)
    {
        Environment.Exit(0);
    }
}

是否有更有效的方法来执行此操作,也许在初始 if 语句中使用一些漂亮的逻辑来检查哪个参数有效,然后对该参数进行一次检查? 使用 4 个 ifs 和 2 个 Array.IndexOf's 似乎很可怕,只是为了支持 2 种不同的方式来允许某人说他们想要输入一个文件...

谢谢!如果这看起来微不足道或者不是 SO 的意思,我很抱歉。不幸的是,我没有任何真正的方法来获得有关我的编码实践的反馈。

您的解决方案无法很好地扩展。想象一下,您有两个不同的参数,有短格式和长格式。那会有多少条件和索引检查?

您最好使用现有工具(例如 Command Line Parser Library)进行参数解析。

您可以根据自己的特定需要编写一个简单的参数解析器,并且仍然支持 "new" 场景。比如你的入口方法中有

// The main entry point for the application.
[STAThread]
static void Main(string[] args)
{
    // Parse input args
    var parser = new InputArgumentsParser();
    parser.Parse(args);
    ....
}

您的 InputArgumentsParser 可能类似于

public class InputArgumentsParser
{
    private const char ArgSeparator = ':';
    private Dictionary<string[],Action<string>> ArgAction = 
        new Dictionary<string[],Action<string>>();

    public InputArgumentsParser()
    {
        // Supported actions to take, based on args
        ArgAction.Add(new[] { "/f", "/file" }, (param) => 
            Console.WriteLine(@"Received file argument '{0}'", param));
    }

    /// Parse collection, expected format is "<key>:<value>"
    public void Parse(ICollection<string> args)
    {
        if (args == null || !args.Any())
            return;

        // Iterate over arguments, extract key/value pairs
        foreach (string arg in args)
        {
            string[] parts = arg.Split(ArgSeparator);
            if (parts.Length != 2)
                continue;

            // Find related action and execute if found
            var action = ArgAction.Keys.Where(key => 
                key.Contains(parts[0].ToLowerInvariant()))
                    .Select(key => ArgAction[key]).SingleOrDefault();

            if (action != null)
                action.Invoke(parts[1]);
            else
                Console.WriteLine(@"No action for argument '{0}'", arg);
        }
    }
}

在这种情况下 /f:myfile.txt/file:myfile.txt 会向控制台吐出

Received file argument 'myfile.txt'

我看到您提供的代码的一个问题是,如果 /ffile 是最后一个参数,它将失败。

如果您不想编写或使用完整的参数解析代码,下面的代码会稍微好一些。

var fileArguments = new string[] { "/f", "file" };

int fileArgIndex = Array.FindIndex(args, 
    arg => fileArguments.Contains(arg.ToLowerInvariant()));

if (fileArgIndex != -1 && fileArgIndex < args.Length - 1)
{
    inputFile = args[fileArgIndex + 1];

    if (!File.Exists(inputFile))
    {
        Environment.Exit(0);
    }
}