2012-01-10 71 views
0

我想創建一個通用Exists()命令類,它能夠爲任何LinqToSQL類的公共屬性(字段)的任何組合構造一個where子句表)在我的datacontext(數據庫)。Expression.Lambda <Func<T,bool>>說'T'找不到

如果根據MSDN的代碼片段編寫了以下代碼,並且發現我無法成功運行代碼,除非我明確聲明Expression.Lambda參數的實體類型(在本例中爲MyApp.Data.Organization) Expression.Call語句。

換句話說,

Expression.Lambda<Func<tblType,bool>>(predBody, new ParameterExpression[] { pe })); 

不工作,但是,

Expression.Lambda<Func<MyApp.Data.Organization,bool>>(predBody, new ParameterExpression[] { pe })); 

確實工作。我想要類似前者的東西,所以這個方法在我的數據上下文中對所有的LinqToSQL類都是通用的。

我已驗證Expression.Call語句之前的所有代碼均正常工作,並且會生成正確的謂詞。我需要更改什麼以保持參數類型的泛型,以便相同的代碼可以用於數據上下文中的任何LinqToSQL類?

修正爲清晰度 看來我使用T作爲變量是令人困惑的事情。下面是修改後的代碼:

OrganizationCriteria criteria = new OrganizationCriteria { OrganizationId = 2 }; 
using (var ctx = ContextManager<MyApp.Data.MyAppDataContext>.GetManager(myConnectionString, false)) { 
       IQueryable tbl = ctx.DataContext.GetTable(criteria.EntityType).AsQueryable(); 
       Type tblType = tbl.ElementType; 

       ParameterExpression pe = Expression.Parameter(tblType, "Item"); 

       Expression left; 
       Expression right; 
       Expression prev = null; 
       Expression curr = null; 
       Expression predBody = null; 
       foreach (KeyValuePair<string, object> kvp in criteria.StateBag) { 
        prev = curr; 
        object val = kvp.Value; 
        if (val is System.String) { 
         left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
         right = Expression.Constant(kvp.Value.ToString()); 
        } 
        else { 
         left = Expression.Property(pe, tblType.GetProperty(kvp.Key)); 
         right = Expression.Constant(kvp.Value, tblType.GetProperty(kvp.Key).PropertyType); 
        } 
        curr = Expression.Equal(left, right); 

        if (prev != null) { 
         predBody = Expression.AndAlso(prev, curr); 
        } 
        else { 
         predBody = curr; 
        } 
       } 

       MethodCallExpression whereCall = Expression.Call(
        typeof(Queryable), 
        "Where", 
        new Type[] { tblType }, 
        tbl.Expression, 
        Expression.Lambda<Func<tblType,bool>>(predBody, new ParameterExpression[] { pe })); 

       var results = tbl.Provider.CreateQuery(whereCall); 
} 
+0

那麼,哪裏來* T來自? – BoltClock 2012-01-10 19:06:21

+0

@BoltClock他想創建一個接受類型參數「T」的方法,因此在創建表達式時不能指定特定的「T」。 – CodesInChaos 2012-01-10 19:07:38

+0

答案是使用Expression.Lambda()的非泛型重載。因此,替換: Expression.Lambda >(predBody,新ParameterExpression [] {PE}) 與 Expression.Lambda(predBody,新ParameterExpression [] {PE}) 做訣竅, – FuzzyCoder 2012-01-10 20:29:29

回答

1

在你的代碼,T是一個變量,而不是一個類型;你不能使用變量作爲泛型類型參數(即使它是一個變量類型Type

+0

謝謝托馬斯。我認爲使用T作爲聲明的局部變量是令人困惑的事情。我在原始文章的代碼中將其更改爲tblType。 – FuzzyCoder 2012-01-10 19:50:27

+1

@FuzzyCoder你的tblType仍然是一個變量,而不是一個類型。這不是你如何使用泛型。您必須在方法簽名中傳入T。 – 2012-01-10 20:22:57

0

它看起來像你試圖訪問T作爲一種類型 - 記住它實際上是一個泛型類型參數。如果您想使用實際類型,請使用typeof(T)。例如,該行:

ParameterExpression pe = Expression.Parameter(T, "Item"); 

應爲這樣:

ParameterExpression pe = Expression.Parameter(typeof(T), "Item"); 
+0

謝謝。請用更明確的代碼查看我修改過的帖子。當我試圖在Expression.Lambda <>()調用中使用除已知類型以外的任何其他類型時,出現編譯器錯誤。在運行時間之前,如何在不知道輸入參數類型的情況下如何使其工作? – FuzzyCoder 2012-01-10 19:53:38

0

你必須類型參數傳遞到包含你的代碼的方法(或作爲您的類的類型參數) :

void SomeMethod<T>() { 
    ...  
    Expression.Lambda<Func<T,bool>> ... 
    ... 
} 
0

由於tblType是在運行時才知道,你只能通過反射調用Expression.Lambda<Func<T, bool>>()。假設你知道如何得到正確的MethodInfo的靜態Lambda方法的期望過載:

var funcType = typeof(Func<,>).MakeGenericType(tblType, typeof(bool)); 
var genericMethodInfo = typeof(Expression).GetMethod("Lambda", ... 
var methodInfo = genericMethodInfo.MakeGenericMethod(funcType); 
var expression = (Expression)methodInfo.Invoke(... 

但得到正確的MethodInfo是遠離瑣碎與所有這些重載。

0

答案是使用Expression.Lambda()的非泛型重載。因此,更換:

Expression.Lambda<Func<tblType,bool>>(predBody, new ParameterExpression[] { pe }) 

Expression.Lambda(predBody, new ParameterExpression[] { pe }) 

的伎倆,我現在對任何領域的任何查詢表中完全通用的方法。

相關問題