简体   繁体   English

C#扩展方法而不是迭代

[英]C# Extension method instead of iteration

I was wondering, if there is an extension method that allow me to iterate a List and let me do the same thing with every item in the list. 我想知道,如果有一个扩展方法允许我迭代List并让我对列表中的每个项目做同样的事情。 For example: 例如:

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

This removes every element wichs fulfill the condition. 这将删除满足条件的每个元素。 But, what if I have this: 但是,如果我有这个:

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

Of course, the real code is a little more complex than this. 当然,真正的代码比这复杂一点。 My objective is to, instead of a foreach use an extension method, I have found List<T>.ForEach() but I can't get it to work, and this method does not exist in a var list. 我的目标是,我找到List<T>.ForEach()而不是foreach使用扩展方法,但我无法使它工作,并且此方法不存在于var列表中。 I found too .Select<> , .Where<> but this returns values, and in my method there is no need to return any value. 我也找到了。选择.Select<> .Where<>在哪里.Where<>但这会返回值,在我的方法中不需要返回任何值。

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

anotherList.AddRange(convertedItems);

or 要么

anotherList = convertedItems.ToList();

and if you want to make it shorter: 如果你想缩短它:

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

I'm not sure I see why you want an extension method here. 我不确定为什么你想要一个扩展方法。 List<T>.ForEach() will do mostly what you like but your existing foreach loop is both idiomatic and readable. List<T>.ForEach()将主要执行您喜欢的操作,但您现有的foreach循环既是惯用的又是可读的。 Is there a reason that you can't just write a normal function to do this? 有没有理由你不能只写一个正常的函数来做这个?

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

In general if you find that you need to mutate items and not return values you don't want to use LINQ or query operators. 通常,如果您发现需要改变项而不返回值,则不希望使用LINQ或查询运算符。 Just use a foreach . 只需使用foreach

Edit: The answers suggesting Select() would work for this simple code, however you state 编辑:建议Select()的答案适用于这个简单的代码,但是你说

the real code is a little more complex than this 真正的代码比这复杂一点

Which suggests to me that you may have to mutate some other state during iteration. 这告诉我你可能不得不在迭代期间改变其他状态。 The Select method will defer this mutation until the sequence is materialized; Select方法将推迟此突变,直到序列实现为止; this will probably give you strange results unless you're familiar with how LINQ queries defer execution and capture outer variables. 除非您熟悉LINQ查询如何延迟执行并捕获外部变量,否则这可能会给您带来奇怪的结果。

It's trivial to write your own ForEach extension. 编写自己的ForEach扩展是微不足道的。 I include the following in all of my code: 我在所有代码中都包含以下内容:

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

You can accomplish this via a Select statement: 您可以通过Select语句完成此操作:

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

Here is how you use ForEach with a lambda expression: 以下是使用lambda表达式的ForEach的方法:

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

However as you can see it looks remarkably similar to what you already have! 但是你可以看到它看起来与你已经拥有的非常相似!

Alternatively it looks to me like Select might be a better match for what you want to do: 另外,在我看来, 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);
});

If you want to perform an action as part of an iteration, you might want to consider the .Do method which is part of the Interactive Extensions. 如果要在迭代过程中执行操作,可能需要考虑作为Interactive Extensions一部分的.Do方法。 See http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return . 请参见http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return

You can easily create an extension method to do this: 您可以轻松创建扩展方法来执行此操作:

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

and you could then call it like this: 然后你可以这样称呼它:

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

Edit: Here is another method for doing the same. 编辑:这是另一种做同样的方法

As far as 'built-in' goes there is no .ForEach() ; 就“内置”而言,没有.ForEach() ; however I think .Aggregate() would be the most appropriate option here (if you absolutely and utterly want a built-in function). 但我觉得.Aggregate()在这里是最合适的选择(如果你绝对想要一个内置函数)。

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

You can obviously just write your own extension methods: 您显然可以编写自己的扩展方法:

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

NB: The reason I don't create a ForEach like everyone else, is because Microsoft didn't include it because, by design Linq methods always return a value, or list of values. 注意:我不像其他人一样创建ForEach的原因是因为Microsoft没有包含它,因为通过设计Linq方法总是返回一个值或值列表。

Specifically to your question, .Select<T> will do the trick. 特别是对你的问题, .Select<T>将成功。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM