Как обновить значение в списке с помощью LINQ

У меня есть список, который я хочу обновить с помощью LINQ.

class Student
{
    private string name;
    private int marks;
    public string Name { get; set;}
    public int Marks { get; set; }
    public Student(string name, int marks)
    {
        Name = name;
        Marks = marks;
    }
}

List<Student> myList = new List<Student>();
myList.Add(new Student("John", 10));
myList.Add(new Student("Tom", 20));

Теперь я хочу обновить список с помощью LINQ, чтобы обновлялись только отметки Джона. Я использую следующий синтаксис:

myList.Where(w => w.Name == "Tom").Select(w=> { w.Marks = 35; return w});

Но это не обновляет данные в myList. Может кто-нибудь сказать мне, где я иду не так.


person user3625024    schedule 05.05.2015    source источник
comment
LINQ используется для запроса данных, которые не обновляются. Лучше сделать это с помощью цикла foreach.   -  person Rahul Singh    schedule 05.05.2015
comment
Я попробовал foreach(item in myList.where(w => w.Name == Tom)) { item.Marks = 35; } но получаю сообщение об ошибке: невозможно изменить члены элемента 'item', потому что это 'переменная итерации foreach'   -  person user3625024    schedule 05.05.2015
comment
Ваш код в том виде, в котором он был опубликован, не компилируется — отсутствуют скобки, несоответствующие типы данных, несогласованный ввод заглавных букв, скрытие полей в конструкторе и т. д. Если вы публикуете что-то, что ближе к исходному коду и фактически компилируется, проблема может быть очевидным. В нынешнем виде простой foreach после вашего запроса должен работать.   -  person D Stanley    schedule 05.05.2015
comment
Код, который вы утверждаете, генерирует «невозможно изменить элементы» элемента. Это сгенерировало бы это, если бы Student было struct, а не class. Предоставленный вами пример кода не компилируется. Можете ли вы предоставить фактический код, который вы используете?   -  person Charles Mager    schedule 05.05.2015


Ответы (9)


LINQ предназначен для запросов, а не для обновления данных. Используйте LINQ, чтобы получить элементы, которые вы хотите изменить, а затем измените их в цикле foreach:

foreach ( var tom in myList.Where(w => w.Name == "Tom")) {
    tom.Marks = 35;
}

Демо.

person Sergey Kalinichenko    schedule 05.05.2015
comment
Это дает ошибку - невозможно изменить члены «элемента», потому что это «переменная итерации foreach». - person user3625024; 05.05.2015
comment
IEnumerable нельзя изменить - person Ehsan Sajjad; 05.05.2015
comment
Это не должно давать ошибки. Это совершенно прекрасный код, который также выполняет модификацию, не совсем уверен в отрицательном голосовании. - person Habib; 05.05.2015
comment
@EhsanSajjad В этом коде нет ничего, что могло бы попытаться изменить IEnumerable. С другой стороны, изменение членов IEnumerable - это 100% честная игра. - person Sergey Kalinichenko; 05.05.2015
comment
@user3625024 user3625024 Вы не должны получать никаких ошибок при условии, что ваш класс Student такой же, как показано в вашем вопросе. Я добавил демо, чтобы показать, как это работает. - person Sergey Kalinichenko; 05.05.2015

Пытаться:

myList .Where(w=> w.Name  == "dTomi").ToList().ForEach(i => i.Marks  = 35);
person SHIBIN    schedule 29.03.2017
comment
Это ничего не объясняет, а ОП спрашивает, что они делают не так. Ответы, содержащие только код, гораздо более ценны, когда они также содержат объяснение. - person Gert Arnold; 02.04.2017

Select(), как и любой другой метод LINQ, не изменяет исходную коллекцию, а возвращает новую коллекцию.

Таким образом, вы должны либо назначить эту новую коллекцию myList:

myList = myList.Where(w => w.Name == "Tom").Select(w => { w.Marks = 35; return w}).ToList();

или назначьте свойство Marks в отдельном цикле foreach

myList.Where(w => w.Name == "Tom").ToList().ForEach(w => w.Marks = 35);
person Prayag    schedule 16.11.2018
comment
Добро пожаловать в Stack Overflow! Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для будущих читателей, и эти люди могут не знать причин вашего предложения кода. - person Kurt Van den Branden; 16.11.2018
comment
@KurtVandenBranden, хотя это старый пост, но вы хотите сказать, что читатели в будущем не смогут прочитать вопрос, чтобы понять, почему это предложение кода здесь? Потому что я прочитал все ответы и понял их все, несмотря на то, что некоторые из них не содержат объяснений. - person Garth Sebastian; 22.08.2020

Как указывали другие, LINQ предназначен для запроса данных, а не для выполнения обновлений.

Вы должны повторить свой список и изменить свои значения, например:

foreach (var student in myList)
{
    if (student.Name == "Tom")
    {
        student.Marks = 35;
    }
}

Or

foreach (var student in myList.Where(r => r.Name == "Tom"))
{
    student.Marks = 35;
}

Используйте то, что, по вашему мнению, лучше передает намерение.


но вот интересная вещь:

Если у вас есть утверждение типа:

myList.Where(w => w.Name == "Tom").Select(w => w.Marks = 35).ToList();

Без присвоения результата обратно myList приведенный выше запрос изменит значение в исходном списке. Помните, что это побочный эффект и это правильный способ обновления. Эту модификацию можно объяснить тем, что ссылочный параметр передается методу и изменяется там. Но главное, этого всегда следует избегать. Это плохая практика, которая может привести к очень запутанному коду. Используйте LINQ только для запросов.

person Habib    schedule 05.05.2015
comment
+1 Это указывает на важный момент, который сводил меня с ума, поскольку многие сообщения содержат ваш анти-шаблон в качестве ответа, и мне было интересно, правильно ли я понял Q в LINQ. Спасибо :-) - person GGleGrand; 18.05.2016
comment
См. этот пост для получения дополнительной информации: stackoverflow.com/questions/1776387/ - person GGleGrand; 18.05.2016

Вышеупомянутое может быть достигнуто, просто присвоив значение коллекции.

myList = myList
        .Where(w => w.Name == "Tom")
        .Select(w=> { w.Marks = 35; return w})
        .ToList();
person Sathish    schedule 08.07.2018

как насчет старого доброго цикла for

for(int i = 0; i < myList.Count; i++)
if (myList[i].Name  == "Tom")
{
    myList[i].Marks = 35;
    break;
}
person ASh    schedule 05.05.2015

хорошо, код @dasblinkenlight должен работать, но вы также можете попробовать что-то вроде этого

 var query = from x in list
             where x.Name = yourcondition
             select new { x };
foreach(var item in query)
   item.x.FieldToUpdate = SetValue;
person user2726374    schedule 05.05.2015

Это довольно неуклюже, но работает и не зависит от передачи ссылки. Он создает новый список на основе старого.

var myList=myList.Select(l=>new Student { 
   l.Name,
   Marks=l.Name=="Tom"?35:l.Marks}).ToList();

Или еще глупее:

var myList=myList.Where(l=>l.Name!="Tom").Union(
  myList.Where(l=>l.Name=="Tom").Select(l=>new Student { 
   l.Name,
   Marks=35})).ToList();
person Robert McKee    schedule 05.05.2015

Объекты хранятся по ссылке в списке, поэтому вы можете восстановить объект через linq, а затем отредактировать, он будет отражать изменения в списке.

Пример

    static void Main(string[] args)
        {
            List<Entity> testList = new List<Entity>()
            {
                new Entity() {Id = 1, Text = "Text"},
                new Entity() {Id = 2, Text = "Text2"}
            };

            Console.WriteLine($"First text value:{testList[1].Text}");

            Entity entityToEdit = testList.FirstOrDefault(e => e.Id == 2);
            if (entityToEdit != null)
                entityToEdit.Text = "Hello You!!";

            Console.WriteLine($"Edited text value:{testList[1].Text}");
            
            Console.ReadLine();
        }

 internal class Entity
    {
        public int Id { get; set; }
        public String Text { get; set; }
    }

Протестировав приложение, вы получите следующий результат:

Первое текстовое значение: Text2

Отредактированное текстовое значение: Привет!

person Final Nemael    schedule 02.04.2017
comment
Другие ответы уже сделали это. Я не думаю, что ваш ответ многое добавляет к этому. - person Gert Arnold; 02.04.2017