为什么表达式树不能包含带有命名参数的规范?

52

使用AutoMapper时,我遇到了一个很好地适合使用命名参数的地方:

.ForMember(s => s.MyProperty, opt => opt.MapFrom(s => BuildMyProperty(s, isAdvanced: false)))

但是编译器提示我:

表达式树可能不包含命名参数规范

所以我只能回到:

.ForMember(s => s.MyProperty, opt => opt.MapFrom(s => BuildMyProperty(s, false)))

有人知道为什么编译器在这种情况下不允许使用命名参数吗?

1个回答

42

考虑以下内容:

static int M() { Console.Write("M"); return 1; }
static int N() { Console.Write("N"); return 2; }
static int Q(int m, int n) { return m + n; }
...
Func<int> f = ()=>Q(n : N(), m: M());
Expression<Func<int>> x = ()=>Q(n : N(), m: M());
Func<int> fx = x.Compile();
Console.WriteLine(f());
Console.WriteLine(fx());

希望你同意,最后两行代码应该做同一件事情,对吧?也就是打印出NM3

那么,你想让表达式树转换生成哪些调用来确保这一点呢?其实没有!因此我们面临以下选择:

  1. 在表达式树库中实现此功能。在表达式树降低引擎中添加一个变换,以保留命名参数的执行顺序。在 Compile 方法中实现考虑执行顺序的代码。
  2. 使 x = ()=>Q(n : N(), m: M()); 实际上被实现为 x = ()=>Q(M(), N()); 并且与非表达式树版本不兼容。
  3. 在表达式树中禁止使用命名参数。实现相应的错误消息。

方法 (1) 虽好但昂贵。方法 (2) 行不通;我们不能良心地介绍这种"陷阱"。方法 (3) 便宜却烦人。

我们选择了(3)。


1
我认为这个错误信息应该被记录下来。换句话说,搜索msdn上的确切错误信息字符串应该为我们提供这个澄清。http://social.msdn.microsoft.com/Search/en-US?query=%22An%20expression%20tree%20may%20not%20contain%20a%20named%20argument%20specification%22&ac=8 - payo
2
@BrandonLinton:开发、测试、文档编写和维护都需要花费很高的成本,特别是与其提供的非常小的好处相比。我们本可以选择在一开始就支持它——毕竟,VB一直都有用于方法调用的命名参数——但我们选择不这样做。 - Eric Lippert
2
难道没有第四个选项:“只要按照相同的顺序,允许在表达式树中使用命名参数”吗?对于 record 类型来说,在主构造函数中按照与构造函数定义相同的顺序使用命名参数是比较常见的。 - DrPhil
4
@DrPhil: 如果十年前我回答这个问题时有记录存在,那么这个选项可能会出现在我的考虑中。 - Eric Lippert
1
@AradAlvand:不对。这个解释令人不满意。准确的解释并不能保证它令人满意!记住,我们不需要为不实施某个功能提供理由。相反,必须对该功能的成本进行合理的辩解。编译器是开源的,如果你认为这是一个好的利用你的时间的方式,可以随意实现它。 - undefined
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接