简体   繁体   English

C# 解构和重载

[英]C# deconstruction and overloads

While investigating the new features in C# 7.x, I created the following class:在研究 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;
        }
    }
}

And the following test code:以及以下测试代码:

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

If the Person class includes only the SECOND Deconstruct overload, the code compiles and runs fine ("Dennis was born a Friday").如果 Person 类仅包含 SECOND Deconstruct 重载,则代码编译并运行良好(“Dennis 出生于星期五”)。 But as soon as the first overload is added to Person, the compiler starts complaining, the error message being:但是一旦将第一个重载添加到 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)以下方法或属性之间的调用不明确:'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)

I've read the MSDN and GitHub documentation, but it is not clear to me why the compiler cannot determine that the only applicable overload is the second, given the inner tuple pattern on the left side of the assignment.我已经阅读了 MSDN 和 GitHub 文档,但我不清楚为什么编译器无法确定唯一适用的重载是第二个,因为赋值左侧的内部元组模式。 Any clarification will be appreciated.任何澄清将不胜感激。

To understand what's going on, it's important to remember that in the expression:要了解发生了什么,重要的是要记住表达式中的内容:

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

the (_, DayOfWeek dow) part is not a tuple. (_, DayOfWeek dow)部分不是元组。 It's a second deconstruct.这是第二次解构。 So the compiler cannot choose between just using your second Deconstruct to satisfy the five parameters (via deconstructing the tuple to the last two parameters), or taking the day parameter from the first one and then attempting to find a Deconstruct on int to satisfy that part.因此,编译器不能选择只使用第二个Deconstruct来满足五个参数(通过将元组解构为最后两个参数),或者从第一个参数中获取day参数,然后尝试在int上找到Deconstruct以满足该部分.

To see this in action, comment out the second Deconstruct , then add:要查看此操作,请注释掉第二个Deconstruct ,然后添加:

static class MyDeconstruct
{
    public static void Deconstruct(this int i, out int dayNumber, out DayOfWeek dayOfWeek) =>
        (dayNumber, dayOfWeek) = (i, (DayOfWeek)i);
}

At that point, the code once again compiles just fine.在这一点上,代码再次编译得很好。

Using the same syntax for tuples and deconstructs brings many advantages.对元组和解构使用相同的语法会带来许多优势。 As you have discovered though, it has the disadvantage when you mix the two as the compiler has no way of knowing you want (_, DayOfWeek dow) to be a tuple in your deconstruct, when it's valid deconstruct syntax.但是,正如您所发现的那样,当您将两者混合使用时,它有一个缺点,因为编译器无法知道您希望(_, DayOfWeek dow)在您的解构中成为一个元组,当它是有效的解构语法时。

However, there still seems to be a severe limitation to the behaviour of compiler to choose which Deconstruct to use, even when it's provided with sufficient type information to resolve the expression.然而,编译器选择使用哪个Deconstruct的行为似乎仍然存在严重限制,即使它提供了足够的类型信息来解析表达式。 It takes a very simple approach of matching the arity (number of parameters) only.它只需要一种非常简单的方法来匹配 arity(参数数量)。 So if two Deconstruct methods exist with the same number of parameters, it can't choose between them.因此,如果存在两个参数数量相同的Deconstruct方法,则无法在它们之间进行选择。 For example,例如,

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

ought to work just fine as we have told it the type of the fourth parameter and thus there is now only one Deconstruct that matches.应该可以正常工作,因为我们已经告诉它第四个参数的类型,因此现在只有一个Deconstruct匹配。 Yet it still complains it can't choose between the two.然而它仍然抱怨它不能在两者之间做出选择。 I've therefore raised an issue with the C# team to see if that can be improved in a future version of the language.因此,我向 C# 团队提出了一个问题,看看是否可以在该语言的未来版本中进行改进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM