2010-11-30 17 views
6

Kullanıcının seçebileceği bir filtre seti sağlamak istiyorum ve her filtre bir Expression<Func<X, bool>>'a karşılık gelecektir. Bu yüzden, kullanılabilir öğelerin ('Joe', 'Steve', 'Pete' vb.) Dinamik bir listesini almak ve bu adlara dayalı olarak "kodlanmış" filtrelerden oluşan bir koleksiyon oluşturmak ve kullanıcının seçmesine izin vermek isteyebilirim hangi filtreleri kullanmak ister. Sorunum, dinamik listeden bir dize değerine dayanarak ifademi "sabit kodlamaya" çalıştığımda bile, ifadenin değeri, bana göre, bana görünen, anonim bir türden asılı bir özellik olarak saklanmasıdır (ve Anon türünü nasıl serileştireceğimi bilmiyorum). Üzgünüm, bu kafa karıştırıcıysa, bunun nasıl telaffuz edileceğinden emin değilim.LINQ: Değer temelli referans nasıl zorlanır?

İşte benim örnek kod:

public class Foo 
    { 
     public string Name { get; set; } 
    } 
    static void Main(string[] args) 
    { 
     Foo[] source = new Foo[] 
      { 
       new Foo() { Name = "Steven" } , 
       new Foo() { Name = "John" } , 
       new Foo() { Name = "Pete" }, 
      }; 

      List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>(); 
      foreach (Foo f in source) 
      { 
       Expression<Func<Foo, bool>> exp = x => x.Name == f.Name; 
       filterLst.Add(exp); 
      } 
    } 
} 

Benim sorunum benim ifade vücutta baktığınızda baktığınızda aşağıdaki gibi okur olmasıdır:

(x.Name = value(ConsoleApplication1.Program+<>c__DisplayClass3).value) 

Ne, ne zaman gerçekten Bunun için kodumu değiştirirsem

(yerine, o kesin var

(x.Name = "Steven") 
: Birincisi böyle okumak için istediğiniz olduğu ly ne alıyorum:

 Expression<Func<Foo, bool>> exp = x => x.Name == "Steven"; 

)

ben İfade içine yapışmasını önce yerel bir dize değerine benim değer zorlama denedim ama işe görünmüyor:

List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>(); 
    foreach (Foo f in source) 
    { 
     string value = f.Name; 
     Expression<Func<Foo, bool>> exp = x => x.Name == value; 
     filterLst.Add(exp); 
    } 

Bir dizeye bildirilen yerel bir değişken kullanıyorum bile, neden (veya gerçekten nasıl) hala anonim bir türe baktığını anlamıyorum. Bu işi istediğim gibi yapmanın bir yolu var mı?

+0

(expression-tree yapısını göstermek için yanıt güncellendi) –

+0

Bize daha karmaşık bir senaryoyu basitleştiriyor musunuz? Bir dizi nesne özelliğini filtrelemenin daha kolay yolları vardır. –

+0

@Jonas: Evet, gerçek senaryonumu biraz basitleştirdim. Her zaman Name özelliğini sabit bir dizeye karşı filtrelemeyi gerçekten istemiyorum; Aslında daha karmaşık nesnelerle uğraşıyorum ve kullanıcıya farklı özellikler veya çoklu özellik koşullarına dayanan birkaç "filtre" koleksiyonunu veriyorum. Nihayetinde, bu "filtreler" in tümü, bir sorgu oluşturmak için bir IQueryable kaynak listesine eklediğim aynı nesne tipine (İfade ) soyutlanır. – Steven

cevap

7

Anon-type, aslında, değişkenlerin yakalamasının yakalamasını gerçekleştirmek için kullandığı derleyici tarafından üretilen türüdür. delegeleri ile yakalamayı el ile uygulayarak kesebilirsiniz, ancak ifade ağaçlarına derlenmiş lambda ifadeleriyle değil.

İki seçenek:

  • inşa

ikincisi aslında çok kötü değil anon türlerini nasıl işleneceğini öğrenmek Expression.Constant vb yoluyla kodu explicitely ifade ağacı; Bunlar genellikle tamamen MemberExpression vardır, ancak etrafta bazı kodları tek tek ele alacağım. Aynı zamanda ifade ağacının oluşturulmasına örnekler verebiliyorum, ama şu anda bir PC'de değilim ve iPod yazmak için kendini iyi düşünmüyorum ...

özetinden soruyu oku İlk seçeneğe ikinci saniyeden daha fazla bakıyorum.

Oh, ve dikkat edin;)


Edit; söz konusu ilk foreach kodu azılı l-değeri yakalama sorununa duyarlı görünüyor: Ben bir PC buldum; p

 var param = Expression.Parameter(typeof(Foo), "x"); 
     var body = Expression.Equal(
      Expression.PropertyOrField(param, "Name"), 
      Expression.Constant(f.Name, typeof(string))); 

     var exp = Expression.Lambda<Func<Foo, bool>>(body, param); 
     filterLst.Add(exp); 
+0

Bu, benim yapmam gereken gibi görünüyor, ama lambdayı almayı ve sadece bunu doğrudan üretmeyi umuyordum ... Sanırım küçük bir iş beni öldürmeyecek :) Kötü şöhretli I-Değer yakalama sorunu nedir? – Steven

+0

@Steven - verdiğiniz ilk kod bloğunda, ben * bekliyoruz * tüm filtreleri '' Pete ''karşı bulacaksınız. Çünkü * değişkeni * (değişkenin * değeri * değil) yakalarsınız ve döngü değişkeni döngü dışında (teknik olarak) * dışarısıdır ve her 3 ifade arasında paylaşılır. –

+0

Yanıt için teşekkürler. Bunu biraz düşünmek zorundaydım ama sanırım anlıyorum. Eğer haklıysam, sorun şu ki, her yinelemenin farklı bir versiyonunu alacağımı varsaydım: (ConsoleApplication1.Program + <> c__DisplayClass3) (belki de __DisplayClass4, __DisplayClass5?), Ama bu referans noktaları benim Döngü bittiğinde, her zaman bir "Pete" ismine sahip olan "f" referansı. Beri çoktan bitene kadar farketmezdim, bu yüzden uyarıyı takdir ediyorum. – Steven

4

Marc Gravell cevabı, doğru ve İşte ilk tercihini şu şekilde uygulayabilirsiniz:

Ancak bu genellikle gerekli değildir. For döngüsünün ikinci örneğiniz tüm büyük LINQ sağlayıcılarıyla çalışmalıdır. Sabitleri kullanmak için ifadeye ihtiyacınız var mı?

+0

(Ayrıca bir süre önce eklediğim düzenlemeye de bakın ...) –

+0

Evet, gönderdikten sonra fark ettim. : P – StriplingWarrior

+0

Size hala çabalarınız için sahne verdim;) – Steven

İlgili konular