c#扩展方法,而不是迭代

本文关键字:迭代 扩展 方法 | 更新日期: 2023-09-27 18:07: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<>,但这返回值,在我的方法中不需要返回任何值。

c#扩展方法,而不是迭代

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});

我不知道为什么要在这里使用扩展方法。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查询如何延迟执行和捕获外部变量。

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

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

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

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

下面是如何使用ForEach和lambda表达式:

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,
}));
List<MyObjectType> list = new List<MyObjectType>();
list.ForEach((MyObjectType item) => {
    object MyObject = new object() 
    {
        MyObject.propertyone = item.property,
        MyObject.propertytwo = somevalue
    };
    anotherlist.Add(MyObject);
});

如果你想要执行一个动作作为迭代的一部分,你可能想要考虑. do方法,它是交互式扩展的一部分。见http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return。

您可以轻松地创建一个扩展方法来做到这一点:

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);

编辑:这里是另一个方法做同样的。

就'内置'而言,没有.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的原因是微软没有包含它,因为按照设计,Linq方法总是返回一个值,或一个值列表。

特别针对你的问题,.Select<T>可以解决这个问题。

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