开发者

C# Extension method instead of iteration

I was wondering, if there is an extension method that allow me to iterate a List and l开发者_Go百科et me do the same thing with every item in the 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. I found too .Select<>, .Where<> but this returns values, and in my method there is no need to return any value.


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. 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. Just use a foreach.

Edit: The answers suggesting Select() would work for this simple code, however you state

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; this will probably give you strange results unless you're familiar with how LINQ queries defer execution and capture outer variables.


It's trivial to write your own ForEach extension. 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:

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


Here is how you use ForEach with a lambda expression:

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:

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. See 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(); however I think .Aggregate() would be the most appropriate option here (if you absolutely and utterly want a built-in function).

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.

Specifically to your question, .Select<T> will do the trick.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜