如何在匿名方法中使用ValueTuple的命名特性?
解决ValueTuple在Select中使用命名特性的编译问题
嘿,我来帮你搞定这个命名元组的编译问题!你遇到的核心问题是lambda参数的语法写法不符合C#规则,再加上源元组本身是匿名的(没有预定义成员名),导致代码无法通过编译。
错误原因分析
你原来的代码写法:
var projection1 = valueTuples.Select(((string s, char c, int i) tuple) => tuple.i);
这里的问题在于,C#不允许你用嵌套括号的方式声明lambda参数——你不能把带命名的元组类型放在一组括号里,再给它加个参数名tuple。另外,你的源集合是匿名元组IEnumerable<(string, char, int)>(成员默认是Item1/Item2/Item3),即使你给元组类型加了s/c/i的命名,编译器也不会自动把源元组的Item3关联到i,除非你用正确的解构方式。
正确的写法示例
下面给你几种可行的解决方案,按需选择:
1. 直接在lambda参数中解构命名(最简洁)
不需要额外的参数名,直接给元组成员命名,然后直接使用命名后的变量:
IEnumerable<(string, char, int)> valueTuples = new[] { ("First", '1', 1), ("Second", '2', 2), ("Third", '3', 3) }; var projection1 = valueTuples.Select((string s, char c, int i) => i);
编译器会按位置把源元组的Item1映射到s,Item2到c,Item3到i,直接返回i即可。
2. 保留参数名并显式指定命名元组类型
如果你想通过参数名访问成员,可以这样写(注意不要嵌套括号):
var projection1 = valueTuples.Select(( (string s, char c, int i) tuple ) => tuple.i);
这里的命名s/c/i是可选的,不过编译器依然按位置匹配源元组的成员。
3. 定义源集合时直接使用命名元组(推荐)
从根源上解决问题,在声明源集合时就给元组成员命名,这样后续使用时可以直接通过命名访问:
// 定义时就指定元组成员的名字 IEnumerable<(string s, char c, int i)> valueTuples = new[] { ("First", '1', 1), ("Second", '2', 2), ("Third", '3', 3) }; // 直接通过命名成员访问,代码更清晰 var projection1 = valueTuples.Select(tuple => tuple.i);
为什么另外两段代码能编译?
projection2用tuple.Item1:因为匿名元组的成员默认就是Item1/Item2/Item3,编译器能识别,所以没问题。- 你提到的
projection3(Select(((string...)应该是省略了部分类型声明,符合lambda参数的语法规则,所以能通过编译。
内容的提问来源于stack exchange,提问作者mikevg
相关产品推荐
相关产品推荐

