Как использовать функцию именования ValueTuple с анонимными методами? - PullRequest
0 голосов
/ 28 апреля 2018

Я хотел бы использовать функцию именования 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 Ответ

0 голосов
/ 28 апреля 2018

У вас есть список неназванных кортежей (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.

Тем не менее, даже с исправлением, которое я считаю, использование именованного кортежа с самого начала - лучший путь. Тогда вам не нужно указывать имена снова и снова в каждой лямбде (и эти имена могут даже отличаться, что делает все это еще более запутанным).

...