LINQ : 새 개체를 만들지 않고 개체를 선택하고 속성을 변경하십시오.


218

새 개체를 만들고 모든 속성을 수동으로 설정하지 않고 LINQ 쿼리 결과 개체의 일부 속성을 변경하고 싶습니다. 이게 가능해?

예:

var list = from something in someList
           select x // but change one property

7
아래 예제와 같이 선언적 구문을 사용하여이를 수행 할 수있는 JaredPar의 답변을 기반으로 확장 메소드를 작성했습니다. 그것을 확인하십시오 : blog.robvolk.com/2009/05/…
Rob Volk

3
@RobVolk, 링크가 죽은 것처럼 보입니다-새로운 링크가 있습니까? 여기 아카이브입니다 - LINQ : 개체를 선택하지만, 새로운 객체 생성하지 않고 일부 속성을 변경
KyleMit

blog.robvolk.com/2009/05/… 찾을 수 없음 DNS 오류
Kiquenet

1
미안합니다! 올바른 주소는 다음과 같습니다. robvolk.com/…
Rob Volk

답변:


380

쿼리 구문이 무엇인지 잘 모르겠습니다. 그러나 다음은 확장 된 LINQ 표현 예제입니다.

var query = someList.Select(x => { x.SomeProp = "foo"; return x; })

이것이하는 것은 익명의 방법과 표현을 사용하는 것입니다. 이를 통해 하나의 람다에서 여러 명령문을 사용할 수 있습니다. 따라서 속성을 설정하고 객체를이 간결한 방법으로 반환하는 두 가지 작업을 결합 할 수 있습니다.


4
@Rob, 쉽지 않습니다. 그 일을하는 구문은 ... 읽을 수 없습니다. var query = 목록에서 그것으로부터 선택 ((Func <Foo>) (() => {it.x = 42; return;})) ();
JaredPar

35
"명령문 본문이있는 람다 식을 식 트리로 변환 할 수 없습니다"오류가 발생합니다. LINQ to SQL이 아니므로 조언이 있습니까?
surya

2
@spiderdevil +1 당신을 위해-당신은 불일치를 싫어하지 않습니까? Linq to SQL / EF가 아닌 Linq to Object에서만 코드가 작동하는 상황에 처한 것은 이번이 처음이 아닙니다. 이것은 여기 에 해결책 일지 모르지만 시간이 없기 때문에 아직 사용하려고하지 않았습니다.
dyslexicanaboko 2019

11
@surya Linq to SQL로 시도 할 때받은 메시지입니다. ToList()전에 트릭을 추가하는 것 같습니다. 왜 그런지 모르겠습니다. Entity Framework 인 경우에도 작동하지 않습니다.
Raziel

5
@surya ToList ()를 호출하면 실제로 데이터를 다시 메모리로 가져옵니다. 따라서 실제로 Linq to SQL이 아닙니다.
Oak

60

모든 요소의 속성을 업데이트하려는 경우

someList.All(x => { x.SomeProp = "foo"; return true; })

3
EF (Entity Framework) : IEnumerable의 모든 객체에서 속성을 바꾸려면 받아 들인 대답이 효과적이었습니다. 나를위한 작업 코드 : var myList = _db.MyObjects.Where (o => o.MyProp == "bar"). AsEnumerable (). Select (x => {x.SomeProp = "foo"; return x;}) ;
firepol

32

나는 이것을 선호합니다. 다른 linq 명령과 결합 될 수 있습니다.

from item in list
let xyz = item.PropertyToChange = calcValue()
select item

24

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

나는 이것을 좋아한다. 내 질문은 첫 번째 예에서 u> 10이 목록에 없으면 어떻게 될까? null 검사를 추가하고 작동하는 것 같습니다. 또한 LHS는 u를 v. +1로 명명했습니다. 매우 간결합니다.
desaivv

11

표준 쿼리 연산자로는 불가능합니다. 언어 통합 업데이트가 아니라 언어 통합 쿼리입니다. 그러나 확장 방법으로 업데이트를 숨길 수 있습니다.

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

1
기본 컬렉션을 업데이트하려는 것은 아닙니다. 결과 수집 속성을 업데이트하려고합니다.
Michael Brennt

4
그럼 LINQ는 구조적 약자 SQL 대체 쿼리 언어,하지만 여전히 할 수있는 기능 능력을 노출 UPDATE, DELETEINSERT. 그래서 나는 의미론 이이 기능을 방해하는 것이라고 주장하지 않을 것입니다.
KyleMit

5

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

변경하지 않아도 항상 반품하십시오. 이런 식으로 목록에 유지됩니다.


1

우리는 종종 새로운 객체를 만들지 않고 색인 값과 목록의 첫 번째 및 마지막 표시기를 포함하려고합니다. 이를 통해 기존 클래스를 수정하지 않고 목록의 첫 번째 항목인지 마지막 항목인지 알 필요없이 목록에서 항목의 위치, 열거 등을 알 수 있습니다.

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 {}

0

최고의 해결책이라고 생각되는 답변을 찾지 못했습니다.

"선택"을 사용하여 데이터를 수정하는 것이 가능하지만, 단지 트릭이 필요합니다. 어쨌든, "선택"은 그런 것이 아닙니다. Linq는 데이터가 필요하기 전에 실행되지 않기 때문에 "ToList"와 함께 사용될 때 수정을 실행합니다. 어쨌든 가장 좋은 해결책은 "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);
            ;
            }
        }
    }

"foreach"전에 linq를 선택할 수도 있습니다 ...


0
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변경 사항과 함께 반환 된 모든 항목이 포함됩니다)


이것이 작동하는 동안 OP는 for each루프 를 작성하지 않고 LINQ 문을 작성하는 방법을 묻고 있다고 생각합니다 .
fujiiface


-3
User u = UserCollection.Single(u => u.Id == 1);
u.FirstName = "Bob"

1
이 스레드 에서 기존 답변 을 복제 할 필요가 없습니다 . 해당 답변에 대한 의견이 있으면 여기에 배치하십시오.
KyleMit
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.