2010-08-10 9 views
6

İfadenin bölümleri argüman olarak iletildiğinde nasıl bir ifade ağacı oluşturabilirim?İfadeleri İfade Ağacında Birleştirme

E.g. ne bunlar gibi ifade ağaçlar oluşturmak istiyorsa: ancak dolaylı bunları oluşturarak

IQueryable<LxUser> test1(IQueryable<LxUser> query, string foo, string bar) 
{ 
    query=query.Where(x => x.Foo.StartsWith(foo)); 
    return query.Where(x => x.Bar.StartsWith(bar)); 
} 

:

IQueryable<LxUser> test2(IQueryable<LxUser> query, string foo, string bar) 
{ 
    query=testAdd(query, x => x.Foo, foo); 
    return testAdd(query, x => x.Bar, bar); 
} 

IQueryable<T> testAdd<T>(IQueryable<T> query, 
    Expression<Func<T, string>> select, string find) 
{ 
    // how can I combine the select expression with StartsWith? 
    return query.Where(x => select(x) .. y => y.StartsWith(find)); 
} 

Sonuç:

örnekleri (pek mantıklı vermemekle birlikte üzgünüm ama bunu basit tutmaya çalışıyorum), işte sonuç (teşekkürler Quartermeister).

FindText ile başlayan veya eşit olan bir dizeyi aramak için Linq-to-Sql ile kullanılabilir.

public static IQueryable<T> WhereLikeOrExact<T>(IQueryable<T> query, 
    Expression<Func<T, string>> selectField, string findText) 
{ 
    Expression<Func<string, bool>> find; 
    if (string.IsNullOrEmpty(findText) || findText=="*") return query; 

    if (findText.EndsWith("*")) 
    find=x => x.StartsWith(findText.Substring(0, findText.Length-1)); 
    else 
    find=x => x==findText; 

    var p=Expression.Parameter(typeof(T), null); 
    var xpr=Expression.Invoke(find, Expression.Invoke(selectField, p)); 

    return query.Where(Expression.Lambda<Func<T, bool>>(xpr, p)); 
} 

ör

var query=context.User; 

query=WhereLikeOrExact(query, x => x.FirstName, find.FirstName); 
query=WhereLikeOrExact(query, x => x.LastName, find.LastName); 

cevap

5
Sen, başka bir ifade yapılıyor demektir bir ifade oluşturmak için Expression.Invoke kullanabilirsiniz

ve Expression.Lambda oluşturmak için Birleşik ifade için yeni lambda ifadesi. Böyle bir şey:

IQueryable<T> testAdd<T>(IQueryable<T> query, 
    Expression<Func<T, string>> select, string find) 
{ 
    Expression<Func<string, bool>> startsWith = y => y.StartsWith(find); 
    var parameter = Expression.Parameter(typeof(T), null); 
    return query.Where(
     Expression.Lambda<Func<T, bool>>(
      Expression.Invoke(
       startsWith, 
       Expression.Invoke(select, parameter)), 
      parameter)); 
} 

iç Expression.Invoke ifade select(x) temsil eder ve dış bir select(x) tarafından döndürülen değerine y => y.StartsWith(find) çağrı temsil eder.

Ayrıca ikinci bir lambda kullanmadan startswith çağrısı temsil etmek Expression.Call kullanabilirsiniz: Genellikle

IQueryable<T> testAdd<T>(IQueryable<T> query, 
    Expression<Func<T, string>> select, string find) 
{ 
    var parameter = Expression.Parameter(typeof(T), null); 
    return query.Where(
     Expression.Lambda<Func<T, bool>>(
      Expression.Call(
       Expression.Invoke(select, parameter), 
       "StartsWith", 
       null, 
       Expression.Constant(find)), 
      parameter)); 
} 
+0

Teşekkürler, ilk cevabım tam olarak aradığım şeydi! – laktak

+0

Burada önemli bir not, LINQ2SQL ve LINQ2Entities ile çalışacak, ancak EF-EF ile hayır, en iyi bilinenler için, 'Expression.Invoke' komutunu uygulayamaz. – nicodemus13

3

Bu Works:

public IQueryable<T> Add<T>(IQueryable<T> query, Expression<Func<T, string>> Selector1, 
        Expression<Func<T, string>> Selector2, string data1, string data2) 
{ 
    return Add(Add(query, Selector1, data1), Selector2, data2); 
} 

public IQueryable<T> Add<T>(IQueryable<T> query, Expression<Func<T, string>> Selector, string data) 
{ 
    var row = Expression.Parameter(typeof(T), "row"); 
    var expression = 
     Expression.Call(
      Expression.Invoke(Selector, row), 
      "StartsWith", null, Expression.Constant(data, typeof(string)) 
     ); 
    var lambda = Expression.Lambda<Func<T, bool>>(expression, row); 
    return query.Where(lambda); 
} 

Sen gibi kullanın:

IQueryable<XlUser> query = SomehowInitializeIt(); 
query = Add(query, x => x.Foo, y => y.Bar, "Foo", "Bar"); 
1

sen (IQueryable Arayüzü kullanarak) descirbed şekilde bunu yapma ama daha ziyade kullanmak Expression<Func<TResult, T>> gibi ifadeler. Bunu söyledikten sonra, bir sorguya daha yüksek sıralı fonksiyonlar (örneğin, where veya select) yazınız ve istenen işlevselliği "dolduracak" ifadeleri ileteceksiniz.

Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) 

fonksiyonu her bir elemanı olarak adlandırılır, ikinci değişken olarak bir temsilci alır:

Örneğin, Enumerable.Where yöntemin imza düşünün. Bu temsilci tarafından döndürdüğünüz değer, geçerli öğeyi (sonuçta dahil edip etmeyeceği) vermesi durumunda, yüksek sıra işlevine işaret eder.

Queryable.Where<TSource>-Methode (IQueryable<TSource>, Expression<Func<TSource, Boolean>>) 

Biz daha yüksek mertebeden fonksiyonunun aynı desen gözlemlemek, ancak bunun yerine bir Func<> temsilci bir İfade alır:

Şimdi, Queryable.Where bir göz atalım. Bir ifade, temel olarak kodunuzun veri temsilidir.Bu ifadeyi derlemek size gerçek (yürütülebilir) bir temsilci verecektir. Derleyici, Expression<...>'a atadığınız lambdalardan ifade ağaçları oluşturmak için çok ağır bir kaldırma işlemi gerçekleştirir. İfade ağaçları, açıklanan kodu bir SQL Server Veri Tabanı gibi farklı veri kaynaklarına karşı derlemeyi mümkün kılar.

ne aradığınız düşünüyorum seçici olduğunu sizin örneğe geri gelmek için. Bir seçici her giriş elemanını alır ve bir projeksiyonunu döndürür. İmza şu gibi görünüyor: Expression<Func<TResult, T>>. bir seçici içindeki geçmek için

Expression<Func<int, string>> numberFormatter = (i) => i.ToString(); // projects an int into a string 

, kod aşağıdaki gibi bakmak gerekir: Örneğin bu bir belirleyebildiğinde

IQueryable<T> testAdd<T>(IQueryable<T> query, Expression<Func<string, T>> selector, string find) 
{ 
    // how can I combine the select expression with StartsWith? 
    return query.Select(selector) // IQueryable<string> now 
       .Where(x => x.StartsWith(find)); 
} 
Bu seçici istenen giriş dizesi proje sağlayacak

yazın. Umarım niyetinizi doğru bir şekilde aldım, başarmaya çalıştığınız şeyi görmek zor.