表达式Lambda<;Func<;T、 bool>>;说';T';找不到
本文关键字:gt lt 找不到 Lambda bool 表达式 Func | 更新日期: 2023-09-27 18:19:59
我正在尝试创建一个通用的Exists()命令类,该类能够为我的数据上下文(数据库)中ANYLinqToSQL类(表)的公共属性(字段)的ANY组合构造where子句。
如果已经根据MSDN中的代码段编写了以下内容,并且发现除非明确声明Expression.Call语句的Expression.Lambda参数的实体类型(在本例中为MyApp.Data.Organization),否则我无法成功运行代码。
换句话说,
Expression.Lambda<Func<tblType,bool>>(predBody, new ParameterExpression[] { pe }));
不起作用,但是
Expression.Lambda<Func<MyApp.Data.Organization,bool>>(predBody, new ParameterExpression[] { pe }));
确实有效。我想要类似前者的方法,这样该方法对我的数据上下文中的所有LinqToSQL类都是通用的。
我已经验证了Expression.Call语句之前的所有代码都运行良好,并将生成正确的谓词。为了使参数Type保持泛型,以便相同的代码适用于数据上下文中的任何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 );
}
在代码中,T
是一个变量,而不是类型;不能将变量用作泛型类型参数(即使它是Type
类型的变量)
看起来您正试图将T
作为一个类型来访问——请记住,它实际上是一个泛型类型参数。如果要使用实际类型,请使用typeof(T)
。例如,这一行:
ParameterExpression pe = Expression.Parameter(T, "Item");
应该这样读:
ParameterExpression pe = Expression.Parameter(typeof(T), "Item");
您必须将类型参数传递到包含代码的方法中(或作为类的类型参数):
void SomeMethod<T>() {
...
Expression.Lambda<Func<T,bool>> ...
...
}
由于tblType
仅在运行时已知,因此只能使用反射调用Expression.Lambda<Func<T, bool>>()
。假设您知道如何获得静态Lambda
方法所需过载的正确MethodInfo:
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绝非易事。
答案是使用Expression.Lambda()的非泛型重载。因此,替换:
Expression.Lambda<Func<tblType,bool>>(predBody, new ParameterExpression[] { pe })
带有
Expression.Lambda(predBody, new ParameterExpression[] { pe })
完成了这个技巧,现在我有了一个完全通用的方法来查询任何字段上的任何表。