在研究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重载,则代码将编译并运行良好(“Dennis出生于星期五”)。但是,当第一个重载添加到Person时,编译器便开始提示,错误消息是:



我已经阅读了MSDN和GitHub文档,但是我不清楚为什么在赋值左侧的内部元组模式的情况下,为什么编译器无法确定唯一适用的重载是第二个。任何澄清将不胜感激。

最佳答案

要了解正在发生的事情,请务必在表达式中记住这一点:

(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);
}

到那时,代码再次编译就可以了。

对元组和解构使用相同的语法会带来很多好处。正如您已经发现的那样,当将两者混合使用时,它有一个缺点,因为编译器无法知道在有效的deconstruct语法中,(_, DayOfWeek dow)是您的deconstruct中的元组。

但是,即使为编译器提供了足够的类型信息来解析表达式,选择使用哪种Deconstruct的行为似乎仍然受到严格的限制。它采用一种非常简单的方法来仅匹配Arity(参数数量)。因此,如果存在两个带有相同数量参数的Deconstruct方法,则无法在它们之间进行选择。例如,
(string name, _, _, int day) = dh;

应该告诉我们第四个参数的类型,它应该可以正常工作,因此现在只有一个Deconstruct可以匹配。然而,它仍然提示不能在两者之间进行选择。 I've therefore raised an issue with the C# team,以查看是否可以在该语言的将来版本中对其进行改进。

关于c# - C#解构和重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47195668/

10-10 19:26