【问题标题】:C# Extension method instead of iterationC# 扩展方法而不是迭代
【发布时间】:2011-09-07 16:22:57
【问题描述】:

我想知道,是否有一种扩展方法可以让我迭代 List 并让我对列表中的每个项目执行相同的操作。例如:

.RemoveAll(x => x.property == somevalue)

这会删除所有满足条件的元素。但是,如果我有这个怎么办:

foreach(object item in lstObjects)
{
    object MyObject = new object();
    MyObject.propertyone = item.property
    MyObject.propertytwo = somevalue;
    anotherlist.Add(MyObject);
}

当然,真正的代码比这复杂一点。我的目标是,而不是 foreach 使用扩展方法,我找到了 List<T>.ForEach() 但我无法让它工作,并且这个方法在 var 列表中不存在。我也找到了.Select<>.Where<>,但这会返回值,在我的方法中不需要返回任何值。

【问题讨论】:

  • 不能让它工作?为什么不?这就是你想要的。
  • “我们不是在寻找简单的方法”-@BlackCath 应该回答 :)
  • 嗨! @bzim 我的时间不多了,所以在 msdn 或示例中进行研究以了解为什么我的尝试不起作用会消耗时间,而我没有。至 stukselbax:XD 哈哈

标签: c# generics extension-methods


【解决方案1】:
var convertedItems = lstObjects.Select(item => 
{
    object MyObject = new object();
    MyObject.propertyone = item.property
    MyObject.propertytwo = somevalue;
    return MyObject;
});

anotherList.AddRange(convertedItems);

anotherList = convertedItems.ToList();

如果你想让它更短:

var convertedItems = lstObjects.Select(item => 
    new object {propertyone = item.property, propertytwo = somevalue});

【讨论】:

  • @#vc 74:不喜欢。与迭代近似中的行数相同,并且不易读。但我不会 -1。
  • 对于 OP:请注意,LINQ 延迟评估,这使得此代码与您的代码比它最初出现的更等效。
  • @Daniel:OP 没有要求更高的可读性,他要求在不使用 foreach 的情况下执行此操作。 vc74 的代码还具有可链接的优点,这是恕我直言,“LINQ”的主要优点之一。
  • @Daniel,这样更好吗? OP 没有提到他是想支持可读性还是代码简洁......
【解决方案2】:

我不确定我明白你为什么要在这里使用扩展方法。 List<T>.ForEach() 将主要做你喜欢的事情,但你现有的 foreach 循环既惯用又可读。您是否有理由不能只编写一个普通函数来执行此操作?

public void DoMyThing(IList<object> objects) {
  foreach (var obj in objects) {
    someOtherList.Add(new MyObj() {
      item1 = obj
    });
  }
}

一般来说,如果您发现需要改变项目而不是返回值,您就不想使用 LINQ 或查询运算符。只需使用foreach

编辑:建议Select() 的答案适用于这个简单的代码,但是你说

真正的代码比这个复杂一点

这对我来说意味着您可能必须在迭代期间改变一些其他状态。 Select 方法将推迟这个突变,直到序列实现;除非您熟悉 LINQ 查询如何延迟执行并捕获外部变量,否则这可能会给您带来奇怪的结果。

【讨论】:

    【解决方案3】:

    编写自己的 ForEach 扩展很简单。我在所有代码中都包含以下内容:

        public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action )
        {
            foreach (T item in collection)
            {
                action(item);
            }
        }
    

    【讨论】:

      【解决方案4】:

      您可以通过 Select 语句完成此操作:

      var newList = lstObjects.Select(o => 
                            new { propertyone = o.property, 
                                  propertytwo = somevalue }).ToList();
      

      【讨论】:

        【解决方案5】:

        这是您如何使用 ForEachlambda 表达式:

        lstObjects.ForEach(item =>
        {
            MyObject obj = new MyObject();
            obj.propertyone = item.property;
            obj.propertytwo = somevalue;
            anotherlist.Add(obj);
        });
        

        但是,正如您所见,它看起来与您已有的非常相似!

        另外,在我看来,Select 可能更适合您想做的事情:

        anotherList.AddRange(lstObjects.Select(item => new MyObject()
        {
            propertyone = item.property,
            obj.propertytwo = somevalue,
        }));
        

        【讨论】:

          【解决方案6】:
          List<MyObjectType> list = new List<MyObjectType>();
          
          list.ForEach((MyObjectType item) => {
              object MyObject = new object() 
              {
                  MyObject.propertyone = item.property,
                  MyObject.propertytwo = somevalue
              };
          
              anotherlist.Add(MyObject);
          });
          

          【讨论】:

            【解决方案7】:

            如果您想在迭代中执行某项操作,您可能需要考虑作为交互式扩展一部分的 .Do 方法。见http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return

            【讨论】:

              【解决方案8】:

              您可以轻松地创建一个扩展方法来执行此操作:

              public IEnumerable<T> RemoveAll(this List<T> list, Func<bool, T> condition)
              {
                 var itemsToRemove = list.Where(s => condition(s));
                 list.RemoveAll(itemsToRemove);
              }
              

              然后你可以这样称呼它:

              myList.RemoveAll(x => x.Property == someValue);
              

              编辑:这是 another method 做同样的事情。

              【讨论】:

                【解决方案9】:

                就“内置”而言,没有.ForEach();但是我认为.Aggregate() 将是这里最合适的选择(如果您绝对完全想要一个内置函数)。

                lstObjects.Aggregate(anotherList, (targetList, value) =>
                    {
                        object MyObject = new object();
                        MyObject.propertyone = item.property
                        MyObject.propertytwo = somevalue;
                        targetList.Add(MyObject);
                        return targetList;
                    });
                

                您显然可以编写自己的扩展方法:

                public static IEnumerable<T> Intercept<T>(this IEnumerable<T> values, Action<T> each)
                {
                    foreach (var item in values)
                    {
                        each(item);
                        yield return item;
                    }
                }
                
                public static IEnumerable<T> Intercept<T>(this IEnumerable<T> values, Action<T, int> each)
                {
                    var index = 0;
                    foreach (var item in values)
                    {
                        each(item, index++);
                        yield return item;
                    }
                }
                
                // ...
                a.Intercept(x => { Console.WriteLine(x); }).Count();
                

                注意:我没有像其他人一样创建 ForEach 的原因是,Microsoft 没有包含它,因为按照设计,Linq 方法总是返回一个值或值列表。

                具体到您的问题,.Select&lt;T&gt; 可以解决问题。

                anotherList.AddRange(lstObjects.Select(x => new MyObject()
                {
                  propertyone = x.property,
                  propertytwo = somevalue
                }));
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-11-06
                  • 2017-03-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-10-03
                  相关资源
                  最近更新 更多