【问题标题】:Using LINQ's Zip with a closure that doesn't return a value将 LINQ 的 Zip 与不返回值的闭包一起使用
【发布时间】:2012-06-26 18:24:20
【问题描述】:

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

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

换句话说,我们有点像在两个集合上做一个ForEach(顺便说一句,我知道Eric Lippert thinks about 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;
});

【问题讨论】:

    标签: c# linq func


    【解决方案1】:

    使用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)>
    

    【讨论】:

      【解决方案2】:

      我经常需要对两个集合中的每一对执行动作。 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-26
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 2018-12-19
        • 2013-07-20
        • 2010-12-07
        相关资源
        最近更新 更多