12

免责声明:这个问题是由我个人的好奇心驱动的,而不是实际需要完成某事。所以我的例子是人为的。尽管如此,我认为这是一个很可能会出现的问题。

假设我们正在使用Zip迭代两个序列,调用一个 void 方法,如果发现这对中的一项与另一项不同(因此丢弃任何返回值),该方法只会引发异常。这里的重点不是该方法抛出异常,而是它返回 void。

换句话说,我们做ForEach了两个以上的系列(顺便说一下,我知道Eric Lippert 的想法ForEach,并且完全同意他的观点,从不使用它)。

现在,Zip想要一个Func<TFirst, TSecond, TResult>,所以当然传递等效于的东西是Action<TFirst, TSecond>行不通的。

我的问题是:有没有比这更好的惯用方式(即返回一个虚拟值)?

var collection1 = new List<int>() { ... };
var collection2 = new List<int>() { ... };

collection1.Zip(collection2, (first, second) => 
{
    VoidMethodThatThrows(first, second);
    return true;
});
4

2 回答 2

22

用于Zip()将项目放入对象中,然后foreach按照您选择的方式进行操作(请执行正常foreach循环,而不是错误的ToList/ForEach 组合)。

var items = collection1.Zip(collection2, (x, y) => new { First = x, Second = y });
foreach (var item in items)
{
    VoidMethodThatThrows(item.First, item.Second);
}

从 C# 7.0 开始,改进的元组支持和解构使其更易于使用。

var items = collection1.Zip(collection2, (x, y) => (x, y));
// or collection1.Zip(collection2, ValueTuple.Create);
foreach (var (first, second) in items)
{
    VoidMethodThatThrows(first, second);
}

此外,.NET Core 和 5 添加了一个重载,它会自动将值配对到元组中,因此您不必进行该映射。

var items = collection1.Zip(collection2); // IEnumerable<(Type1, Type2)>

.NET 6 添加了第三个集合。

var items = collection1.Zip(collection2, collection3); // IEnumerable<(Type1, Type2, Type3)>
于 2012-06-25T13:53:19.377 回答
1

我经常需要对两个集合中的每一对执行一个操作。Zip 方法在这种情况下没有用。

可以使用这种扩展方法ForPair :

public static void ForPair<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second,
    Action<TFirst, TSecond> action)
{
    using (var enumFirst = first.GetEnumerator())
    using (var enumSecond = second.GetEnumerator())
    {
        while (enumFirst.MoveNext() && enumSecond.MoveNext())
        {
            action(enumFirst.Current, enumSecond.Current);
        }
    }
}

因此,对于您的示例,您可以编写:

var collection1 = new List<int>() { 1, 2 };
var collection2 = new List<int>() { 3, 4 };

collection1.ForPair(collection2, VoidMethodThatThrows);
于 2020-12-08T16:35:18.177 回答