Я хочу змінити деякі властивості об'єкта результатів запиту LINQ, не створюючи нового об'єкта та не встановлюючи вручну кожну властивість. Чи можливо це?
Приклад:
var list = from something in someList
select x // but change one property
Я хочу змінити деякі властивості об'єкта результатів запиту LINQ, не створюючи нового об'єкта та не встановлюючи вручну кожну властивість. Чи можливо це?
Приклад:
var list = from something in someList
select x // but change one property
Відповіді:
Я не впевнений, що таке синтаксис запитів. Але ось приклад розширеного виразу LINQ.
var query = someList.Select(x => { x.SomeProp = "foo"; return x; })
Для цього використовується анонімний метод vs та вираження. Це дозволяє використовувати кілька тверджень в одній лямбда. Таким чином, ви можете поєднати дві операції встановлення властивості та повернення об'єкта в цей дещо лаконічний метод.
ToList()
до цього, здається, робить трюк. Не впевнений, чому ви все це отримаєте. Якщо це Entity Framework, він також не працює з цим.
Якщо ви просто хочете оновити властивість для всіх елементів, тоді
someList.All(x => { x.SomeProp = "foo"; return true; })
Я віддаю перевагу цьому. Його можна комбінувати з іншими командами linq.
from item in list
let xyz = item.PropertyToChange = calcValue()
select item
Не повинно бути жодної магії LINQ, яка не дозволяє вам це робити. Не використовуйте проекцію, хоча це поверне анонімний тип.
User u = UserCollection.FirstOrDefault(u => u.Id == 1);
u.FirstName = "Bob"
Це дозволить змінити реальний об'єкт, а також:
foreach (User u in UserCollection.Where(u => u.Id > 10)
{
u.Property = SomeValue;
}
Зі стандартними операторами запитів це неможливо - це інтегрований мовний запит, а не інтегроване оновлення мови. Але ви можете приховати своє оновлення методами розширення.
public static class UpdateExtension
{
public static IEnumerable<Car> ChangeColorTo(
this IEnumerable<Car> cars, Color color)
{
foreach (Car car in cars)
{
car.Color = color;
yield return car;
}
}
}
Тепер ви можете використовувати його наступним чином.
cars.Where(car => car.Color == Color.Blue).ChangeColorTo(Color.Red);
UPDATE
, DELETE
і INSERT
. Тому я б не заперечував, що семантика - це те, що заважає цій функції.
Якщо ви хочете оновити елементи за допомогою Where
пункту, використовуючи .Where (...) обрізає ваші результати, якщо ви зробите це:
mylist = mylist.Where(n => n.Id == ID).Select(n => { n.Property = ""; return n; }).ToList();
Ви можете робити оновлення певних елементів у списку так:
mylist = mylist.Select(n => { if (n.Id == ID) { n.Property = ""; } return n; }).ToList();
Завжди повертайте товар, навіть якщо ви не вносите жодних змін. Таким чином він буде зберігатися в списку.
Ми часто стикаємося з цим, коли хочемо включити в список значення індексу та перший та останній показники без створення нового об’єкта. Це дозволяє вам знати позицію елемента у своєму списку, перерахування тощо, не змінюючи існуючого класу, а потім знати, чи є ви в першому елементі у списку чи останньому.
foreach (Item item in this.Items
.Select((x, i) => {
x.ListIndex = i;
x.IsFirst = i == 0;
x.IsLast = i == this.Items.Count-1;
return x;
}))
Ви можете просто розширити будь-який клас за допомогою:
public abstract class IteratorExtender {
public int ListIndex { get; set; }
public bool IsFirst { get; set; }
public bool IsLast { get; set; }
}
public class Item : IteratorExtender {}
Оскільки я не знайшов тут відповіді, яку вважаю найкращим рішенням, ось мій шлях:
Використовувати "Вибрати" для зміни даних можливо, але лише з хитрістю. У всякому разі, "Вибрати" для цього не робиться. Він просто виконує модифікацію при використанні з "ToList", тому що Linq не виконує до того, як потрібні дані. У будь-якому випадку, найкращим рішенням є використання "foreach". У наступному коді ви можете побачити:
class Person
{
public int Age;
}
class Program
{
private static void Main(string[] args)
{
var persons = new List<Person>(new[] {new Person {Age = 20}, new Person {Age = 22}});
PrintPersons(persons);
//this doesn't work:
persons.Select(p =>
{
p.Age++;
return p;
});
PrintPersons(persons);
//with "ToList" it works
persons.Select(p =>
{
p.Age++;
return p;
}).ToList();
PrintPersons(persons);
//This is the best solution
persons.ForEach(p =>
{
p.Age++;
});
PrintPersons(persons);
Console.ReadLine();
}
private static void PrintPersons(List<Person> persons)
{
Console.WriteLine("================");
foreach (var person in persons)
{
Console.WriteLine("Age: {0}", person.Age);
;
}
}
}
Перед тим, як "передбачити", ви також можете зробити підбірку linq ...
var item = (from something in someList
select x).firstordefault();
Ви отримаєте item
, і тоді ви можете зробити, item.prop1=5;
щоб змінити конкретну властивість.
Або ви хочете отримати список елементів з db і чи змінює він властивість prop1
кожного елемента у цьому поверненому списку на вказане значення? Якщо так, ви можете зробити це (я це роблю в VB, тому що я це краще знаю):
dim list = from something in someList select x
for each item in list
item.prop1=5
next
( list
міститиме всі елементи, повернені із змінами)
for each
циклу.
У 2020 році я використовую MoreLinq
Pipe
метод. https://morelinq.github.io/2.3/ref/api/html/M_MoreLinq_MoreEnumerable_Pipe__1.htm
User u = UserCollection.Single(u => u.Id == 1);
u.FirstName = "Bob"