C#解构和重载 [英] C# deconstruction and overloads

查看:35
本文介绍了C#解构和重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在研究C#7.x的新功能时,我创建了以下类:

While investigating the new features in C# 7.x, I created the following 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类仅包含SECOND Deconstruct重载,则代码将编译并正常运行("Dennis出生于星期五").但是,当第一个重载添加到Person时,编译器便开始抱怨,错误消息是:

If the Person class includes only the SECOND Deconstruct overload, the code compiles and runs fine ("Dennis was born a Friday"). But as soon as the first overload is added to Person, the compiler starts complaining, the error message being:

以下方法或属性之间的调用不明确:'Person.Deconstruct(输出字符串,输出int,输出int,输出int)'和'Person.Deconstruct(输出字符串,输出int,输出int,输出(intDayNumber,DayOfWeek DayOfWeek))'(CS0121)(ValueTuples)

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文档,但对于我来说,不清楚为什么在赋值左侧的内部元组模式下,编译器无法确定唯一适用的重载是第二个.任何澄清将不胜感激.

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. Any clarification will be appreciated.

推荐答案

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

To understand what's going on, it's important to remember that in the expression:

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

(_,DayOfWeek dow)部分不是元组.这是第二次解构.因此,编译器无法选择仅使用第二个 Deconstruct 来满足五个参数(通过将元组解构为最后两个参数),还是选择第一个中的 day 参数一个,然后尝试在 int 上找到一个 Deconstruct 来满足这一要求.

the (_, DayOfWeek dow) part is not a tuple. 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 ,然后添加:

To see this in action, comment out the second Deconstruct, then add:

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.

对元组和解构使用相同的语法会带来很多好处.正如您已经发现的那样,当将两者混合使用时,它有一个缺点,因为编译器无法知道在有效的解构中(_,DayOfWeek dow)是您的解构中的元组语法.

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.

但是,即使为编译器提供了足够的类型信息来解析表达式,选择使用哪个 Deconstruct 的编译器的行为似乎仍然受到严格的限制.它采用一种非常简单的方法来仅匹配Arity(参数数量).因此,如果存在两个具有相同数量参数的 Deconstruct 方法,则无法在它们之间进行选择.例如,

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. It takes a very simple approach of matching the arity (number of parameters) only. So if two Deconstruct methods exist with the same number of parameters, it can't choose between them. For example,

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

应该可以正常工作,就像我们告诉它的第四个参数的类型一样,因此现在只有一个 Deconstruct 可以匹配.然而,它仍然抱怨不能在两者之间进行选择.我因此向C#团队提出了一个问题,以查看是否可以在语言的未来版本.

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. 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#解构和重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆