动态创建Contains筛选LambdaExpression时参数类型不匹配问题排查与解决求助
这个问题的核心原因是你在创建Lambda表达式时,泛型参数用了Func<dynamic, bool>,但你的参数表达式parameter是具体的Kar.Model.Infrastructure.ProjectType类型,两者类型不兼容导致了报错。
错误原因分析
Expression.Lambda<Func<dynamic, bool>>要求委托的第一个参数是dynamic(本质等价于object类型),但你传入的parameter是ProjectType类型的参数表达式,CLR无法将具体类型的参数表达式绑定到object类型的委托参数上,因此抛出了类型不匹配的异常。
解决方案
因为ModelClassType是运行时动态确定的,无法在编译时指定具体的泛型参数,所以不能直接使用Expression.Lambda<Func<T, bool>>这种强类型泛型方法,下面给你两种可行的修复方案:
方案一:使用非泛型Lambda方法+动态执行
如果你不需要强类型委托,只是需要执行表达式逻辑,可以用非泛型的Lambda方法创建表达式,再通过DynamicInvoke执行:
// 替换原代码最后一行 var finalExpression = Expression.Lambda(Body, parameter); // 执行时传入具体的实例 bool result = (bool)finalExpression.DynamicInvoke(yourModelInstance);
方案二:通过反射创建强类型委托(性能更优,推荐)
如果需要配合LINQ查询等强类型场景,可以通过反射构建对应的Func<T, bool>泛型委托类型,再创建委托:
// 构建泛型委托类型:Func<ModelClassType, bool> var delegateType = typeof(Func<,>).MakeGenericType(ModelClassType, typeof(bool)); // 创建强类型Lambda表达式 var finalExpression = Expression.Lambda(delegateType, Body, parameter); // 编译为委托 var funcDelegate = finalExpression.Compile(); // 后续可根据场景通过反射Invoke,或者转换为对应委托类型使用
补充:完善Nullable属性的处理
你最初想要实现的是x => AwaitingTasksIDs.Contains(x.WfmTaskID.Value),目前代码还没处理Nullable的Value属性,这里可以补充一下:
var member = Expression.Property(parameter, propertyName); // 获取Nullable类型的Value属性 var valueMember = Expression.Property(member, "Value"); // 调用Contains时传入valueMember作为参数 Expression Body = Expression.Call(Expression.Constant(AwaitingTasksIDs), methodInfo, valueMember);
注意要确保WfmTaskID确实是Nullable<Guid>类型,否则获取Value属性会出错,也可以提前判断成员类型是否为Nullable类型再做处理。
备注:内容来源于stack exchange,提问作者gwt

