C#解构和重载

时间:2017-11-09 06:54:18

标签: c# c#-7.0

在研究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,编译器就会开始抱怨,错误消息为:

  

以下方法或属性之间的调用是不明确的:'​​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 个答案:

答案 0 :(得分:6)

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

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

(_, DayOfWeek dow)部分不是元组。这是第二次解构。因此编译器无法在仅使用第二个Deconstruct来满足五个参数(通过将元组解构为最后两个参数)或从第一个参数中取day参数然后尝试查找在Deconstructint来满足该部分。

要查看此操作,请注释掉第二个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的行为似乎仍存在严重的限制,即使它提供了足够的类型信息来解析表达式。它只需要一种非常简单的方法来匹配arity(参数的数量)。因此,如果存在两个具有相同数量参数的Deconstruct方法,则它们无法在它们之间进行选择。例如,

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

应该工作得很好,因为我们告诉它第四个参数的类型,因此现在只有一个Deconstruct匹配。然而它仍然抱怨它不能在两者之间做出选择。 I've therefore raised an issue with the C# team看看是否可以在该语言的未来版本中进行改进。