c# - 如何在 C# 中从 lambda 引用方法参数
问题描述
给定这个 lambda
public static Expression<Func<int, int>> Add(int add)
{
return x => x + add;
}
它创建以下调试输出:
.Lambda #Lambda1<System.Func`2[System.Int32,System.Int32]>(System.Int32 $x) {
$x + .Constant<ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0>(ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0).add
}
调试视图显示该字段add
在常量内寻址。
如何动态创建相同的 lambda?
我试过的:
public static Expression<Func<int, int>> Add(int add)
{
var x = Expression.Parameter(typeof(int), "x");
var expr = Expression.Add(x, Expression.Field(Expression.Constant(null), "add"));
return Expression.Lambda<Func<int, int>>(expr, x);
}
导致System.ArgumentException: 'Instance field 'add' is not defined for type 'System.Object''
.
直接使用参数作为常量只会创建值的副本:Expression.Constant(add)
解决方案
诀窍是使用简单的Expression.Constant(add)
or Expression.Constant(add, typeof(int))
(明确表达类型是个好主意,特别是如果值可以是null
)。
至于使用现场方法:你不能,你的第一个版本中的常规编译器也不能。编译器所做的是生成一个闭包,并使用它,即
var obj = new SomeGeneratedClosureType();
obj.add = add; // and now *all* mentions of "add" use obj.add instead
并使用该对象作为常量:
var expr = Expression.Add(x, Expression.Field(Expression.Constant(obj), "add"));
这SomeGeneratedClosureType
是ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0
您的问题代码中的。
但是,不这样做会更高效,更直接 ,直接使用该值即可。编译器不能这样做,因为它需要对值的行为方式保持一定的保证,如果你直接使用这个值是不可能的。
推荐阅读
- node.js - 将订单集合中的订单总和添加到猫鼬中的用户集合
- java - Spring Boot 多个 CommandLineRunner 执行顺序和状态
- bash - 键绑定在 VSCode 集成终端中不起作用
- amazon-web-services - AWS elb 日志 OPTION 请求返回 500 状态码
- arrays - 如何在 2 个 bash 循环中迭代数组列表
- ping - ICMP Ping 不会禁用
- pytorch - 使用 torch DistributedDataParallel 时是否可以有一个中心函数/对象?
- python - 如何从python中用逗号分隔的字符串中找到最长的字符串
- javascript - Swiper.js Carousel 如何用鼠标中键同时控制多个轮播
- python - 为什么 Scrapy CrawlerProcess 将控制权交给它之前的行,导致它和上一行运行 2-3 次?