Метод расширения C # вместо итерации - PullRequest
1 голос
/ 07 сентября 2011

Мне было интересно, есть ли метод расширения, который позволяет мне повторять список и позволяет мне делать то же самое с каждым элементом в списке. Например:

.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(), но я не могу заставить его работать, и этот метод не существует в списке переменных. Я также нашел .Select<>, .Where<>, но это возвращает значения, и в моем методе нет необходимости возвращать какое-либо значение.

Ответы [ 9 ]

3 голосов
/ 07 сентября 2011
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});
1 голос
/ 07 сентября 2011

Я не уверен, что понимаю, зачем вам нужен метод расширения здесь. 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 откладывают выполнение и захватывают внешние переменные.

0 голосов
/ 07 сентября 2011

Что касается «встроенного», то нет .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<T> добьется цели.

anotherList.AddRange(lstObjects.Select(x => new MyObject()
{
  propertyone = x.property,
  propertytwo = somevalue
}));
0 голосов
/ 07 сентября 2011

Вы можете легко создать метод расширения для этого:

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

Редактировать: Вот другой метод для того же.

0 голосов
/ 07 сентября 2011

Если вы хотите выполнить действие как часть итерации, вы можете рассмотреть метод .Do, который является частью Interactive Extensions. Смотри http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return.

0 голосов
/ 07 сентября 2011
List<MyObjectType> list = new List<MyObjectType>();

list.ForEach((MyObjectType item) => {
    object MyObject = new object() 
    {
        MyObject.propertyone = item.property,
        MyObject.propertytwo = somevalue
    };

    anotherlist.Add(MyObject);
});
0 голосов
/ 07 сентября 2011

Вот как вы используете ForEach с лямбда выражением:

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,
}));
0 голосов
/ 07 сентября 2011

Вы можете сделать это с помощью оператора Select:

var newList = lstObjects.Select(o => 
                      new { propertyone = o.property, 
                            propertytwo = somevalue }).ToList();
0 голосов
/ 07 сентября 2011

Писать собственное расширение ForEach просто. Я включаю в свой код следующее:

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