为范围内的每个索引做一些事情

do something foreach Index in a Range

C# 8.0 引入了结构 System.IndexSystem.Range

遍历 System.Range 最简洁的方法是什么?

var owners = new string[] {"Alice", "Bob", "Charlie"};
var pets = new string[] {"Dog", "Cat", "Bird"};

foreach (var index in 1..3) {
    var pet = pets[index];
    var owner = owners[index];
    Console.WriteLine($"{owner} owns a {pet}");
}

上面foreach (var index in 1..3) {行是一个编译错误。

Type 'System.Range' cannot be used in 'foreach' statement because it neither implements 'IEnumerable' or 'IEnumerable', nor has suitable 'GetEnumerator' method which return type has 'Current' property and 'MoveNext' method

如果你想枚举 (owner, pet) 元组,你可以借助 Linq Zip 而不是 Range:

using System.Linq;

...

foreach (var (owner, pet) in owners.Zip(pets, (o, p) => (o, p))) {
  Console.WriteLine($"{owner} owns a {pet}");
}

如果你想要 Skip 第一任主人 (Alice) 和她的宠物 (Dog) 只需添加 Skip(在你的代码中你的范围从 1, 不是来自 0):

foreach (var (owner, pet) in owners.Zip(pets, (o, p) => (o, p)).Skip(1)) {
  Console.WriteLine($"{owner} owns a {pet}");
}

恐怕你无法枚举 System.Range(你可以,请参阅我的编辑),因为它没有实现 IEnumerable<int>。原因是它可能包含集合末尾的索引。

如果需要,您需要使用 for 循环或 Enumerable.Range:

foreach (var index in Enumerable.Range(0, 3)) {
    var pet = pets[index];
    var owner = owners[index];
    Console.WriteLine($"{owner} owns a {pet}");
}

如果您只想获取同一索引处的两个集合的项目,请使用 Enumerable.Zip,如 所示。


编辑:实际上你 可以 使用扩展来完成(致谢 here,注意我的错误修正)

public static class RangeEx
{
    public static RangeEnumerator GetEnumerator(this Range range)
    {
        if (range.Start.IsFromEnd || range.End.IsFromEnd)
        {
            throw new ArgumentException(nameof(range));
        }

        return new RangeEnumerator(range.Start.Value, range.End.Value);
    }

    public struct RangeEnumerator : IEnumerator<int>
    {
        private readonly int _end;
        private int _current;

        public RangeEnumerator(int start, int end)
        {
            _current = start - 1; // - 1 fixes a bug in the original code
            _end = end;
        }

        public int Current => _current;
        object IEnumerator.Current => Current;

        public bool MoveNext() => ++_current < _end;

        public void Dispose() { }
        public void Reset()
        {
            throw new NotImplementedException();
        }
    }
}

有了这个你就可以使用你的代码了:

foreach (int index in 1..3)
{
    Console.WriteLine($"{owners[index]} owns a {pets[index]}");
}

您不能将 foreach 循环与 Range 一起使用,因为它没有实现 IEnumerable 接口。如果你想显示数组的一部分,你只能使用 Range

Range range = 0..2;

var i=range.Start.Value;
foreach (var owner in owners[range])
{
    Console.WriteLine($"{owner} owns a {pets[i]}");
    i++;
}

结果

Alice owns a Dog
Bob owns a Cat

Range range = 1..3;

var i=range.Start.Value;
foreach (var owner in owners[range])
{
    Console.WriteLine($"{owner} owns a {pets[i]}");
    i++;
}

结果

Bob owns a Cat
Charlie owns a Bird

但在你的情况下,使用 for 循环要容易得多

for (var i=0; i <3; i++) Console.WriteLine($"{owners[i]} owns a {pets[i]}");