如何将 ValueTuple 命名功能与匿名方法一起使用?
How do I use the ValueTuple naming feature with anonymous methods?
我想使用 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);
尝试更直接的方法,这不会编译但会出错
更有帮助的留言:
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 语法才能让它工作?
你有一个未命名的元组列表(string, char, int)
(注意没有名字)。因此,使用默认名称 Item1
、Item2
等访问可以正常工作。
但是,您传递给 Select
lamdba 的是命名元组类型:
(string s, char c, int i) tuple) => tuple.i
类型推断似乎没有考虑命名和未命名元组(或两个具有不同名称的命名元组)完全相同,并且在某些情况下使用此类 "different" 类型时推断失败。我不完全确定为什么,也许它甚至是一个错误,或者规范中可能包含某些内容。
但是,根据这些知识,我们可以确定解决问题的最佳方法是从一开始就使用命名元组类型:
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。这确实是一个已确认的错误,甚至已经解决了。没有关于此错误性质的解释。修复应该出现在版本 15.7 中。
即使有修复,我仍然认为从一开始就使用命名元组是最好的方法。然后你就不需要在每个 lambda 中一次又一次地指定名称(而且这些名称甚至可以不同,这使得整个事情更加混乱)。
我想使用 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);
尝试更直接的方法,这不会编译但会出错 更有帮助的留言:
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 语法才能让它工作?
你有一个未命名的元组列表(string, char, int)
(注意没有名字)。因此,使用默认名称 Item1
、Item2
等访问可以正常工作。
但是,您传递给 Select
lamdba 的是命名元组类型:
(string s, char c, int i) tuple) => tuple.i
类型推断似乎没有考虑命名和未命名元组(或两个具有不同名称的命名元组)完全相同,并且在某些情况下使用此类 "different" 类型时推断失败。我不完全确定为什么,也许它甚至是一个错误,或者规范中可能包含某些内容。
但是,根据这些知识,我们可以确定解决问题的最佳方法是从一开始就使用命名元组类型:
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。这确实是一个已确认的错误,甚至已经解决了。没有关于此错误性质的解释。修复应该出现在版本 15.7 中。
即使有修复,我仍然认为从一开始就使用命名元组是最好的方法。然后你就不需要在每个 lambda 中一次又一次地指定名称(而且这些名称甚至可以不同,这使得整个事情更加混乱)。