在研究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文档,但我不清楚为什么编译器无法确定唯一适用的重载是第二个,给定分配左侧的内部元组模式。任何澄清将不胜感激。
答案 0 :(得分:6)
要了解正在发生的事情,请务必记住表达式:
(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
的行为似乎仍存在严重的限制,即使它提供了足够的类型信息来解析表达式。它只需要一种非常简单的方法来匹配arity(参数的数量)。因此,如果存在两个具有相同数量参数的Deconstruct
方法,则它们无法在它们之间进行选择。例如,
(string name, _, _, int day) = dh;
应该工作得很好,因为我们告诉它第四个参数的类型,因此现在只有一个Deconstruct
匹配。然而它仍然抱怨它不能在两者之间做出选择。 I've therefore raised an issue with the C# team看看是否可以在该语言的未来版本中进行改进。