C#解构和重载
C# deconstruction and overloads
在调查 C# 中的新功能时 7.x,我创建了以下 class:
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 class 仅包含 SECOND Deconstruct 重载,则代码可以正常编译和运行 ("Dennis was born a Friday")。但是一旦将第一个重载添加到 Person,编译器就会开始报错,错误消息为:
The call is ambiguous between the following methods or properties: 'Person.Deconstruct(out string, out int, out int, out int)' and 'Person.Deconstruct(out string, out int, out int, out (int DayNumber, DayOfWeek DayOfWeek))' (CS0121) (ValueTuples)
我已经阅读了 MSDN 和 GitHub 文档,但我不清楚为什么编译器无法确定唯一适用的重载是第二个,给定左侧的内部元组模式那作业。如有任何澄清,我们将不胜感激。
要了解发生了什么,请务必记住表达式中的内容:
(string name, _, _, (_, DayOfWeek dow))
(_, DayOfWeek dow)
部分不是元组。这是第二次解构。因此,编译器无法选择仅使用第二个 Deconstruct
来满足五个参数(通过将元组解构为最后两个参数),或者从第一个参数中获取 day
参数然后尝试查找a Deconstruct
on 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
匹配。但它仍然抱怨无法在两者之间做出选择。 I've therefore raised an issue with the C# team 看看是否可以在该语言的未来版本中改进。
在调查 C# 中的新功能时 7.x,我创建了以下 class:
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 class 仅包含 SECOND Deconstruct 重载,则代码可以正常编译和运行 ("Dennis was born a Friday")。但是一旦将第一个重载添加到 Person,编译器就会开始报错,错误消息为:
The call is ambiguous between the following methods or properties: 'Person.Deconstruct(out string, out int, out int, out int)' and 'Person.Deconstruct(out string, out int, out int, out (int DayNumber, DayOfWeek DayOfWeek))' (CS0121) (ValueTuples)
我已经阅读了 MSDN 和 GitHub 文档,但我不清楚为什么编译器无法确定唯一适用的重载是第二个,给定左侧的内部元组模式那作业。如有任何澄清,我们将不胜感激。
要了解发生了什么,请务必记住表达式中的内容:
(string name, _, _, (_, DayOfWeek dow))
(_, DayOfWeek dow)
部分不是元组。这是第二次解构。因此,编译器无法选择仅使用第二个 Deconstruct
来满足五个参数(通过将元组解构为最后两个参数),或者从第一个参数中获取 day
参数然后尝试查找a Deconstruct
on 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
匹配。但它仍然抱怨无法在两者之间做出选择。 I've therefore raised an issue with the C# team 看看是否可以在该语言的未来版本中改进。