带有Eof / Eol / EndOfInput属性的C#/ .NET迭代器

时间:2014-05-05 22:50:15

标签: c# .net collections

我需要用复杂的参数解析命令行。每个参数可以包含0个或更多个子参数。我从这开始:

    static void Main(string[] args)
    {
        var argIterator = ((IEnumerable<string>)args).GetEnumerator();
        ParseArguments(argIterator);
    }

然而事实证明这还不够,因为在任何特定时刻我都需要知道我是否在EndOfInput。虽然MoveNext()返回false,但这可以在解析期间的任何地方发生,并且IEnumerator不会让我知道发生了这种情况,除了调用Current引发异常。我认为这不值得创建自定义枚举类。

我使用的技巧是将所有字符串添加到具有args.length + 1元素的新数组中。附加元素是null。然后我可以有这个扩展方法:

static class EnumeratorExtension
{
    private static bool EndOfInput(this IEnumerator<string> iterator)
    {
        return iterator.Current == null;
    }

}

在任何时候,我都可以致电iterator.EndOfInput()并准确了解是否所有参数都被访问过。但是,这会污染IEnumerator并且不适用于任何集合(仅在最后需要null)。

这似乎是一种常见的需求。有更好的解决方案吗?

2 个答案:

答案 0 :(得分:0)

您没有使用设计使用的IEnumerator

合同IEnumerator指定当您致电MoveNext()时,true的值为“我有一个值且位于Current”且{{1} }意思是“我没有更多的价值”。

如果您想要一种允许您在false返回Current时致电MoveNext()的方法,则需要编写其他内容(因为这与false不匹配'合同。

例如,您可以跳过调用其他处理程序或向其传递IEnumerator对象。

答案 1 :(得分:0)

在您的情况下,最好使用for循环。调查员不是为你正在做的事而设计的。

你可以这样做:

static void Main(string[] args)
{
    foreach (string arg in args)
    {
        ParseArgument(arg);  // Parse each argument individually.
    }
}

如果您需要子参数,那么您可以将逻辑拆分为多个方法:

static void Main(string[] args)
{
    ParseArguments(args);
}

static void ParseArguments(string[] args)
{
    for (int i = 0; i < args.Length; i++)
    {
        switch (args[i])
        {
            // Single arguments. (No sub-arguments)
            case "/a":
            case "/b":
            case "/c":
                ParseArgument(args[i]);  // Parse individual argument(s)
                break;

            // Double-arguments (1 sub-argument)
            case "/username":
            case "/password":
            case "/filepath":
                string nextArg = (i + 1 < args.Length ? args[i + 1] : null);
                ParseArgument(args[i], nextArg);  // Parse individual argument(s)
                i++;
                break;

            // Triple-arguments (2 sub-arguments)
            case "/makeAndModel":
            case "/nameAndAddress":
                string nextArg = (i + 1 < args.Length ? args[i + 1] : null);
                string nextArg2 = (i + 2 < args.Length ? args[i + 2] : null);
                ParseArgument(args[i], nextArg, nextArg2);  // Parse individual argument(s)
                i += 2;
                break;

            // Invalid arguments
            default:
                ShowHelp();
                break;
    }
}

// Parse individual argument(s)
static void ParseArgument(params string[] args)
{
    ...
}

请注意,您还可以通过其他方式实现ParseArgument(params string[] args),例如3种不同的重载方法,每种方法都有不同数量的参数;或者你可以为每个参数实现一个方法(例如ParseUserNameParsePassword等。)


编辑:如果您需要不同数量的子参数,并且您不知道其中有多少个子参数(例如,子参数的数量取决于其实际内容参数),然后您可以执行以下操作:

static void Main(string[] args)
{
    int parsedCount = 0;

    for (int index = 0; index < args.Length; index += parsedCount)
    {
        parsedCount = ParseArguments(args);
    }
}

static int ParseArguments (string[] args, int index)
{
    ...
}

上述情况仍然优于使用枚举器。