在研究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/