我想使用ValueTuple的命名功能如下:
IEnumerable<(string, char, int)> valueTuples = new(string, char, int)[]
{
("First", '1', 1),
("Second", '2', 2),
("Third", '3', 3)
};
var projection1 = valueTuples.Select(((string s, char c, int i) tuple) => tuple.i);
但它没有使用不太有用的错误消息进行编译。但是这些都编译:
var projection2 = valueTuples.Select(tuple => tuple.Item1);
var projection3 = valueTuples.Select(((string, char, int) tuple) => tuple.Item1);
尝试更直接的方法,这不编译BUT给出错误 消息更有帮助:
var projection4 = Enumerable.Select(
valueTuples, ((string s, char c, int i) tuple) => tuple.i);
这导致尝试这个,编译:
var projection5 = Enumerable.Select<(string, char, int), int>(
valueTuples, ((string s, char c, int i) tuple) => tuple.i);
最终启发了这个,编译:
var projection6 = valueTuples.Select<(string, char, int), int>(
((string s, char c, int i) tuple) => tuple.i);
这是IEnumerable扩展方法的一般问题吗? 它似乎不是因为这编译:
var filtered = valueTuples.Where(((string s, char c, int i) tuple) => tuple.i > 1);
为什么我必须使用projection6语法才能使其正常工作?
答案 0 :(得分:5)
您有一个未命名的元组列表(string, char, int)
(请注意,没有名称)。出于这个原因,使用默认名称Item1
,Item2
等进行访问可以正常工作。
但是,传递给Select
lamdba的内容名为元组类型:
(string s, char c, int i) tuple) => tuple.i
似乎类型推断不考虑命名和未命名的元组(或两个具有不同名称的命名元组)完全相同,并且在某些情况下推理失败,而这些&#34;不同&#34;使用的类型。我不完全确定为什么,也许它甚至是一个错误,或者说规范中有些东西可以涵盖那些。
但是,有了这些知识,我们可以发现解决问题的最佳方法是从一开始就使用命名元组类型:
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);
更新:我实际上在Roslyn存储库中找到了issue。它确实是一个确认的错误,它已经解决了。关于这个bug的性质没有解释。修复程序应出现在15.7版中。
即使有一个修复,我认为从一开始就使用命名元组是最好的方法。然后你不需要在每个lambda中反复指定名称(这些名称甚至可以不同,这使得整个事情更加令人困惑)。