LINQ: Bir nesne seçin ve yeni bir nesne oluşturmadan bazı özellikleri değiştirin


218

Yeni bir nesne oluşturmadan ve her özelliği el ile ayarlamadan bir LINQ sorgu sonucu nesnesinin bazı özelliklerini değiştirmek istiyorum. Mümkün mü?

Misal:

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

7
Aşağıdaki gibi açıklayıcı sözdizimini kullanarak bunu başarmanıza izin veren JaredPar'ın cevabını temel alan bir uzatma yöntemi yazdım. Şuna
Rob Volk

3
@RobVolk, bağlantı ölü görünüyor - yeni bir tane mi var? İşte bir arşiv - LINQ: Bir nesne seçin, ancak yeni bir nesne oluşturmadan bazı özellikleri değiştirin
KyleMit

blog.robvolk.com/2009/05/… bulunamadı DNS Hatası
Kiquenet

1
bunun için üzgünüm! ihere doğru adres: robvolk.com/…
Rob Volk

Yanıtlar:


380

Sorgu sözdiziminin ne olduğundan emin değilim. Ancak burada genişletilmiş LINQ ifade örneği verilmiştir.

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

Bunun yaptığı anonim bir yöntem ve ifade kullanmaktır. Bu, bir lambdada birkaç ifade kullanmanıza izin verir. Böylece özelliği ayarlama ve nesneyi bu biraz özlü yönteme döndürme işlemlerini birleştirebilirsiniz.


4
@Rob, Kolay değil. Bu çalışmayı elde etmek için sözdizimi ... en iyi ihtimalle okunamıyor. var query = listeden ondan select ((Func <Foo>) (() => {it.x = 42; döndür;})) ();
JaredPar

35
"Bir deyim gövdesi ile bir lambda ifade bir ifade ağacına dönüştürülemez" hatası alıyorum. LINQ to SQL, herhangi bir tavsiye için değil mi?
surya

2
@spiderdevil +1 sizin için - sadece eşitsizlikten nefret etmiyor musunuz? Bu, kodun Linq to Object / SQL / EF için değil, yalnızca Linq to Object için çalıştığı bir duruma ilk kez girmedim. Bu bir çözüm olabilir burada , ama ben zamanım yok çünkü henüz kullanmaya denemedim.
dyslexicanaboko

11
@surya Linq to SQL ile çalışırken tam olarak aldığım mesaj bu. Öncekini eklemek ToList()hile yapıyor gibi görünüyor. Bunu neden aldýđýndan emin deđilim. Entity Framework ise, bununla da çalışmaz.
Raziel

5
@surya ToList () öğesini çağırdığınızda aslında verileri belleğe geri getiriyorsunuz. Yani artık aslında Linq to SQL değil.
Meşe

60

Yalnızca tüm öğelerdeki özelliği güncellemek istiyorsanız

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

3
EF'de (Entity Framework): IEnumerable'ın tüm nesnelerindeki bir özelliği değiştirmek için kabul edilen cevap benim için çalıştı. Benim için çalışma kodu: var myList = _db.MyObjects.Where (o => o.MyProp == "bar"). AsEnumerable (). (X => {x.SomeProp = "foo"; return x;}) öğesini seçin ;
firepol

32

Bunu tercih ederim. Diğer linq komutlarıyla birleştirilebilir.

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

24

Bunu yapmanıza engel olan herhangi bir LINQ büyüsü olmamalıdır. Anonim bir tür döndürecek olsa da projeksiyonu kullanmayın.

User u = UserCollection.FirstOrDefault(u => u.Id == 1);
u.FirstName = "Bob"

Bu, gerçek nesneyi de değiştirir:

foreach (User u in UserCollection.Where(u => u.Id > 10)
{
    u.Property = SomeValue;
}

Bunu beğendim, sorum ilk örnekte listede bazı u> 10 bulunmazsa ne olur? Bir boş kontrol ekledim ve çalışıyor gibi görünüyor. Ayrıca LHS u. V. +1 olarak adlandırdım. Çok özlü.
desaivv

11

Standart sorgu operatörleri ile mümkün değildir - Dil ile Tümleşik Güncelleme değil, Dil ile Tümleşik Sorgudur. Ancak güncellemenizi uzantı yöntemlerinde gizleyebilirsiniz.

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

Şimdi aşağıdaki gibi kullanabilirsiniz.

cars.Where(car => car.Color == Color.Blue).ChangeColorTo(Color.Red);

1
Temel koleksiyonu güncellemek istemezsiniz. Sonuç toplama özelliğinin güncellenmesini istiyoruz.
Michael Brennt

4
Eh LINQ Structured açılımı SQL yerini Sorgu Dili, ama yine yeteneği yeteneğini ortaya çıkarır UPDATE, DELETEve INSERT. Bu yüzden anlambilimin bu işlevi engelleyen şey olduğunu iddia etmem.
KyleMit

5

Öğeleri bir Wherecümle ile güncellemek istiyorsanız , .Where (...) öğesini kullanarak şunları yaparsanız sonuçlarınız kesilir:

mylist = mylist.Where(n => n.Id == ID).Select(n => { n.Property = ""; return n; }).ToList();

Listedeki belirli öğeler için güncellemeler yapabilirsiniz:

mylist = mylist.Select(n => { if (n.Id == ID) { n.Property = ""; } return n; }).ToList();

Herhangi bir değişiklik yapmasanız bile her zaman ürünü iade edin. Bu şekilde listede tutulacaktır.


1

Sıklıkla yeni bir nesne oluşturmadan bir indeks değeri ve ilk ve son göstergeleri bir listeye dahil etmek istediğimiz yere gideriz. Bu, mevcut sınıfı değiştirmek zorunda kalmadan listenizdeki öğenin konumunu, numaralandırmayı vb. Bilmenizi ve ardından listedeki ilk öğede mi yoksa sonuncusunda mı olduğunuzu bilmenizi sağlar.

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

Herhangi bir sınıfı aşağıdakileri kullanarak genişletebilirsiniz:

public abstract class IteratorExtender {
    public int ListIndex { get; set; }
    public bool IsFirst { get; set; } 
    public bool IsLast { get; set; } 
}

public class Item : IteratorExtender {}

0

Burada en iyi çözümü düşündüğüm cevabı burada bulamadığım için, bu şekilde:

Verileri değiştirmek için "Seç" kullanmak mümkündür, ancak sadece bir hile ile. Her neyse, bunun için "Seç" yapılmaz. "ToList" ile birlikte kullanıldığında sadece değişikliği gerçekleştirir, çünkü Linq veri gerekmeden yürütmez. Her neyse, en iyi çözüm "foreach" kullanmaktır. Aşağıdaki kodda şunları görebilirsiniz:

    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" dan önce, linq seçimi de yapabilirsiniz ...


0
var item = (from something in someList
       select x).firstordefault();

Alacağı itemve sonra yapabileceği item.prop1=5;belirli özelliğini değiştirmek için.

Yoksa db öğelerin bir listesini almak ve prop1o döndürülen listedeki her öğenin özelliği belirtilen bir değere değiştirmesini istiyor musunuz? Eğer öyleyse bunu yapabilirsin (VB'de yapıyorum çünkü daha iyi biliyorum):

dim list = from something in someList select x
for each item in list
    item.prop1=5
next

( listdeğişikliklerinizle birlikte iade edilen tüm öğeleri içerir)


Bu işe yarayacak olsa da, OP bir for eachdöngü yazmak zorunda kalmadan nasıl LINQ deyimi yazmak istediğini düşünüyorum .
fujiiface


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.