C# 使用 Expression.Call 构造 lambda 不喜欢某些类型作为参数?
由于各种原因,我使用表达式树工具动态构建 C# lambda。例如我可以创建一个 Func
public static bool myMethod( object obj ) { … }
// Construct a Func<string,bool>
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (string))};
var callMyMethod = Expression.Call(myMethod, lambdaParams);
var lambda = Expression.Lambda(typeof(Func<string,bool>), callMyMethod, lambdaParams);
var del = (Func<string,bool>)lambda.Compile();
del("foo"); // works
但是,如果我使用相同的代码尝试创建 Func
// Construct a Func<DateTime,bool> or perhaps a struct type fails... why?
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (DateTime))};
var callMyMethod = Expression.Call(myMethod, lambdaParams); // Blows up here…
System.ArgumentException: Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'Boolean myMethod(System.Object)'
所以,字符串有效,而 List
对此的任何帮助将不胜感激。
谢谢, 拍
For various reasons I'm constructing a C# lambda dynamically using the expression tree facilities. e.g. I can make a Func<string,bool> at runtime as shown in the following snippet.
public static bool myMethod( object obj ) { … }
// Construct a Func<string,bool>
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (string))};
var callMyMethod = Expression.Call(myMethod, lambdaParams);
var lambda = Expression.Lambda(typeof(Func<string,bool>), callMyMethod, lambdaParams);
var del = (Func<string,bool>)lambda.Compile();
del("foo"); // works
However if I use the same code to try to make a Func<int,bool> or a Func<DateTime,bool> it blows up where indicated with the following strange exception:
// Construct a Func<DateTime,bool> or perhaps a struct type fails... why?
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (DateTime))};
var callMyMethod = Expression.Call(myMethod, lambdaParams); // Blows up here…
System.ArgumentException: Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'Boolean myMethod(System.Object)'
So, string works and List<string> works but int32 does not work nor does DateTime. What is going on? I don't know how the deep internals of C# work but I am guessing it's due to int really being handled as a primitive and maybe DateTime (being a struct) as well...
Any help with this would be greatly appreciated.
thanks,
Pat
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
据我了解,
Expression.Call
不执行值类型参数的自动装箱。我找不到任何相关文档,但在 此论坛页面。一种解决方法是使用
Expression.TypeAs
。在您的情况下,这应该可行:(
如果只有一个参数,则不需要花哨的 lambda)
根据实际使用情况,您可能必须根据所讨论的类型是否需要检查装箱转换是否必要是值类型。
As I understand it,
Expression.Call
doesn't perform auto-boxing of value-type arguments. I'm unable to find any documentation to that effect, but it is mentioned on this forum page.One workaround would be to explicitly do the boxing conversion in the expression with
Expression.TypeAs
.In your case, this should work:
(You don't need the fancy lambdas if there's only one parameter)
Depending on the real usage, you may have to check if the boxing conversion is necessary depending on whether the type(s) in question is(are) value-type(s).
检查一下:您必须将 DateTime 装箱,因为 DateTime 不是引用类型!
Check this out: you have to box the DateTime, since DateTime isnt' a reference type!