Как использовать функцию именования ValueTuple с анонимными методами?
Я хотел бы использовать функцию именования 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, чтобы заставить это работать?
1 ответ
У вас есть список неназванных кортежей (string, char, int)
(обратите внимание, что нет никаких имен). По этой причине, доступ с использованием имен по умолчанию Item1
, Item2
и так далее отлично работает.
Однако, что вы передаете Select
lamdba назван типом кортежа:
(string s, char c, int i) tuple) => tuple.i
Похоже, что вывод типа не считает именованные и безымянные кортежи (или два именованных кортежа с разными именами) полностью идентичными, и вывод в некоторых случаях дает сбой, когда используются такие "разные" типы. Я не совсем уверен, почему, может быть, это даже ошибка, или, может быть, есть что-то в спецификации, которая покрывает это.
Но с этим знанием мы можем выяснить, что лучший способ решить вашу проблему - это использовать именованный тип кортежа с самого начала:
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. Это действительно подтвержденная ошибка, и она уже устранена. Там нет никаких объяснений о природе этой ошибки. Исправление должно появиться в версии 15.7.
Тем не менее, даже с исправлением, которое я считаю, использование именованного кортежа с самого начала - лучший путь. Тогда вам не нужно указывать имена снова и снова в каждой лямбде (и эти имена могут даже отличаться, что делает все это еще более запутанным).