Использование Linq для запуска метода в коллекции объектов?

Это длинный выстрел, я знаю...

Скажем, у меня есть коллекция

List<MyClass> objects;

и я хочу запустить тот же метод для каждого объекта в коллекции с возвращаемым значением или без него. До Linq я бы сказал:

List<ReturnType> results = new List<ReturnType>();
List<int> FormulaResults = new List<int>();
foreach (MyClass obj in objects) {
  results.Add(obj.MyMethod());
  FormulaResults.Add(ApplyFormula(obj));
}

Я бы люблю, чтобы иметь возможность сделать что-то вроде этого:

List<ReturnType> results = new List<ReturnType>();
results.AddRange(objects.Execute(obj => obj.MyMethod())); 
// obviously .Execute() above is fictitious
List<int> FormulaResults = new List<int>();
FormulaResults.AddRange(objects.Execute(obj => ApplyFormula(obj)));

Я не нашел ничего, что сделает это. Есть ли такая вещь?

Если нет ничего общего, как я уже говорил выше, по крайней мере, возможно, есть способ сделать это для целей, над которыми я сейчас работаю: у меня есть коллекция одного объекта, который имеет класс-оболочку:

class WrapperClass {
  private WrappedClass wrapped;
  public WrapperClass(WrappedClass wc) {
    this.wrapped = wc;
  }
}

В моем коде есть коллекция List<WrappedClass> objects, и я хочу преобразовать ее в List<WrapperClass>. Есть ли какой-то умный способ Linq сделать это, не выполняя утомительный

List<WrapperClass> result = new List<WrapperClass>();
foreach (WrappedClass obj in objects)
  results.Add(new WrapperClass(obj));

Спасибо...

Ответы

Ответ 1

Будет:

results.AddRange(objects.Select(obj => ApplyFormula(obj)));

делать?

или (проще)

var results = objects.Select(obj => ApplyFormula(obj)).ToList();

Ответ 2

Я думаю, что метод расширения Select() может делать то, что вы ищете:

objects.Select( obj => obj.MyMethod() ).ToList(); // produces List<Result> 

objects.Select( obj => ApplyFormula(obj) ).ToList(); // produces List<int>

То же самое для последнего случая:

objects.Select( obj => new WrapperClass( obj ) ).ToList();

Если у вас есть метод void, который вы хотите вызвать, вот трюк, который вы можете использовать с IEnumerable, у которого нет расширения ForEach(), чтобы создать подобное поведение без особых усилий.

objects.Select( obj => { obj.SomeVoidMethod(); false; } ).Count();

Select() будет вызывать последовательность [false] значений после вызова SomeVoidMethod() на каждом [obj] в последовательности объектов. Поскольку Select() использует отложенное выполнение, мы вызываем расширение Count(), чтобы заставить каждый элемент в последовательности, подлежащей оценке. Он работает очень хорошо, когда вы хотите что-то вроде поведения ForEach().

Ответ 3

Если метод MyMethod, который вы хотите применить, возвращает объект типа T, тогда вы можете получить IEnumerable<T> результата метода с помощью:

var results = objects.Select(o => o.MyMethod());

Если метод MyMethod, который вы хотите применить, имеет тип возврата void, то вы можете применить этот метод с помощью:

objects.ForEach(o => o.MyMethod());

Это предполагает, что objects имеет общий тип List<>. Если все, что у вас есть, это IEnumerable<>, вы можете перевернуть свой собственный ForEach метод расширения или применить сначала objects.ToList() и использовать выше синтаксис.

Ответ 4

Компилятор С# отображает выбор LINQ на метод .Select extension, определенный над IEnumerable (или IQueryable, который мы здесь проигнорируем). Фактически этот метод .Select - это именно тот вид функции проецирования, который вы после.

LBushkin корректен, но вы также можете использовать синтаксис LINQ...

var query = from o in objects
   select o.MyMethod();

Ответ 5

http://www.hookedonlinq.com/UpdateOperator.ashx имеет расширенный метод обновления, который вы можете использовать. Или вы можете использовать оператор select, опубликованный другими.

Ответ 6

Вы также можете запустить собственный метод, используя замечательную библиотеку Jon Skeet morelinq

Например, если у вас было свойство text на MyClass, которое вам нужно было изменить во время выполнения, используя метод в том же классе:

objects = objects.Pipe<MyClass>(class => class.Text = class.UpdateText()).ToList();

Этот метод теперь будет реализован на каждом объекте в вашем списке. Я люблю morelinq!