繁体   English   中英

表达式 <Func<T,bool> &gt;说找不到“ T”

[英]Expression.Lambda<Func<T,bool>> Says 'T' could not be found

我正在尝试创建一个通用的Exists()命令类,该类能够为我的数据上下文(数据库)中的任何LinqToSQL类(表)的公共属性(字段)的任何组合构造一个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");

您必须将type参数传递到包含代码的方法中(或作为类的type参数):

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 })

做到了这一点,现在我有了一个完全通用的方法来查询任何字段上的任何表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM