2012-01-10 75 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 }) 

的伎俩,我现在对任何领域的任何查询表中完全通用的方法。

相关问题