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. 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.
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.
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.
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;
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.