чтобы увидеть, может ли это быть улучшено в будущей версии языка.

дуя новые функции в C # 7.x, я создал следующий класс:

using System;
namespace ValueTuples
{
    public class Person
    {
        public string Name { get; }
        public DateTime BirthDate { get; }

        public Person(string name, DateTime birthDate)
        {
            Name = name;
            BirthDate = birthDate;
        }

        public void Deconstruct(out string name,
            out int year, out int month, out int day)
        {
            name  = Name;
            year  = BirthDate.Year;
            month = BirthDate.Month;
            day   = BirthDate.Day;
        }

        public void Deconstruct(out string name,
            out int year, out int month, 
            out (int DayNumber, DayOfWeek DayOfWeek) day)
        {
            name = Name;
            year = BirthDate.Year;
            month = BirthDate.Month;
            day.DayNumber = BirthDate.Day;
            day.DayOfWeek = BirthDate.DayOfWeek;
        }
    }
}

И следующий тестовый код:

using System;
namespace ValueTuples
{
    class MainClass
    {
        static void Main()
        {
            var dh = new Person("Dennis", new DateTime(1985, 12, 27));
            // DECONSTRUCTION:
            (string name, _, _, (_, DayOfWeek dow)) = dh;
            Console.WriteLine($"{name} was born a {dow}");
        }
    }
}

Если класс Person включает только перегрузку SECOND Deconstruct, код компилируется и работает нормально («Деннис родился в пятницу»). Но как только первая перегрузка добавлена в Person, компилятор начинает жаловаться, сообщая об ошибке:

Вызов неоднозначен между следующими методами или свойствами: «Person.Deconstruct (out string, out int, out int, out int)» и «Person.Deconstruct (out string, out int, out int, out (int DayNumber, DayOfWeek») DayOfWeek)) '(CS0121) (ValueTuples)

Я прочитал документацию по MSDN и GitHub, но мне не ясно, почему компилятор не может определить, что единственной применимой перегрузкой является вторая, учитывая шаблон внутреннего кортежа в левой части назначения. Любые разъяснения будут оценены.

Ответы на вопрос(1)

Решение Вопроса

(string name, _, _, (_, DayOfWeek dow))

(_, DayOfWeek dow) часть не кортеж Это вторая деконструкция. Таким образом, компилятор не может выбирать между использованием вашего второгоDeconstruct для удовлетворения пяти параметров (путем деконструкции кортежа до двух последних параметров) или взятияday параметр из первого, а затем пытается найтиDeconstruct наint чтобы удовлетворить эту часть.

Чтобы увидеть это в действии, закомментируйте второйDeconstruct, затем добавьте:

static class MyDeconstruct
{
    public static void Deconstruct(this int i, out int dayNumber, out DayOfWeek dayOfWeek) =>
        (dayNumber, dayOfWeek) = (i, (DayOfWeek)i);
}

В этот момент код снова компилируется просто отлично.

Использование одного и того же синтаксиса для кортежей и деконструкций дает много преимуществ. Однако, как вы обнаружили, у вас есть недостаток, когда вы смешиваете их, так как компилятор не может знать, что вы хотите(_, DayOfWeek dow) быть кортежем в вашей деконструкции, когда это правильный синтаксис деконструкции.

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

(string name, _, _, int day) = dh;

должен работать просто отлично, так как мы указали тип четвертого параметра и, таким образом, теперь есть только одинDeconstruct это соответствует. Тем не менее, он все еще жалуется, что не может выбирать между двумя.Поэтому я поднял проблему с командой C # чтобы увидеть, может ли это быть улучшено в будущей версии языка.

Ваш ответ на вопрос