C# 具有Eof/Eol/EndOfInput属性的C/.NET迭代器
我需要用复杂的参数解析命令行。每个参数可以包含0个或多个子参数。我从这个开始:C# 具有Eof/Eol/EndOfInput属性的C/.NET迭代器,c#,.net,collections,C#,.net,Collections,我需要用复杂的参数解析命令行。每个参数可以包含0个或多个子参数。我从这个开始: static void Main(string[] args) { var argIterator = ((IEnumerable<string>)args).GetEnumerator(); ParseArguments(argIterator); } 在任何时候,我都可以调用iterator.EndOfInput并精确地知道是否访问了所有参数。
static void Main(string[] args)
{
var argIterator = ((IEnumerable<string>)args).GetEnumerator();
ParseArguments(argIterator);
}
在任何时候,我都可以调用iterator.EndOfInput并精确地知道是否访问了所有参数。但是,这会污染IEnumerator,并且不适用于任何只在末尾需要null的集合
这似乎是一个共同的需要。有更好的解决方案吗?您没有按照IEnumerator的设计使用它
IEnumerator指定,当调用MoveNext时,值为true意味着我有一个值,而值为Current和false意味着我没有更多的值
如果您想要一个方法,允许您在MoveNext返回false时调用Current,那么您需要编写其他内容,因为这与IEnumerator的契约不匹配
例如,您可以跳过调用其他处理程序或向它们传递空对象。在您的情况下,最好使用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)
{
...
}
上述方法仍然比使用枚举器要好。将args用作数组并将其传递到ParseArguments中有什么错。然后,您可以在其中使用for循环,并利用数组上的Length属性来确定是否正在解析最后一个参数?这需要沿所有解析器方法传递ref int索引。获取当前元素将始终是args[index]两个值,而不是单个值迭代器.current。Eol的测试将是index>=args.length,再次使用两个值。我更喜欢使用一个表示迭代器的对象。那么为什么不将循环移出ParseArguments呢?然后使用parsearguments[i];在循环内部。您是否可以发布更多的代码,如ParseArguments和它调用的函数之一,以便我们更好地了解您正在尝试执行的操作。示例参数字符串也会很有帮助,尤其是带有子参数的字符串ParseArguments方法只是冰山一角。参数可以有子参数,由其他解析方法ParseOptionFooiterator、ParseOptionK9iterator等解析。到处传递参数和索引似乎不太好。谢谢,但我的问题是,参数可以有不同数量的子参数,你的答案没有考虑到这一点。根据你的要求更新谢谢努力。我知道我可以做这样的事情。这正是我不想做的。我希望迭代器使代码易于阅读,但您不能满足可读性要求。此外,您考虑的是单个级别的子参数,可能不止这些。使用int索引的唯一方法是将ref int index传递给我的所有子解析器,正如我在前面的评论中所说的那样。我觉得这比拥有迭代器更糟糕。我谦虚地不同意。上面的方法将解析逻辑分成两部分,一部分用于提取参数,另一部分用于解析实际内容。这使它更具可读性。使用枚举器肯定会使它更难理解。我已经为另一个可能更符合您要求的场景再次更新了我的答案。我不想调用Current。我只想知道迭代器是否超过了最后一项。我确信它有这些信息,因为它保存索引和参数,所以它可以根据args.length检查索引。@fernacolo:这是一个实现细节。接口只提供Current和MoveNext,因此这些是您唯一可以询问的内容。
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)
{
...
}
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)
{
...
}