Asymmetry of a tuple / decomposition of C # 7 value

Here is the script .

For the function (string a, string b) F() you can deconstruct the returned tuple:

 var (a, b) = F(); (string c, string d) = F(); 

Or you can simply assign it:

 var (a, b) e = F(); (string a, string b) f = F(); var g = F(); // One of these things is not like the others. 

Class deconstructors behave like the first case. For class C with Deconstructor(out string a, out string b) :

 var c = new C(); var (h, i) = c; (string j, string k) = c; 

But the compiler will not use the deconstructor to implicitly convert it to a tuple:

 // Cannot implicitly convert type 'C' to '(string a, string b)' var (a, b) l = c; 

Obviously, you can mechanically write an implicit deconstruction-based transformation:

 public static implicit operator (string a, string b) (C c) { c.Deconstruct(out string a, out string b); return (a, b); } 

Despite the visual similarities in syntax between deconstruction and assignment, assigning a reference to a tuple is not the same as deconstructing a class in variables and then placing them in a new tuple. However, you can implicitly convert (int x, int y) to (double x, double y) . Baskets with variables are a kind of syntactic sugar, where it does what it looks like it does, and don't forget about the implementation details.

If I thought about it, the C # team would think about it, and if they decided not to add β€œmagic” support for implicit conversion, they had a good reason 1 .

Is there a positive reason why automatic implicit conversion would be a bad idea?

Or is it one of those features that were simply not considered valuable enough to justify the cost?


Here is the code that scripts :

 public class Program { public static void Main() { (string a, string b) = F(); (string a, string b) ab = F(); Console.WriteLine($"a: {a} b: {b} ab: {ab}"); var c = new C(); (string d, string e) = c; // Cannot implicitly convert type 'C' to '(string a, string b)' (string a, string b) f = c; Console.WriteLine($"d: {d} e: {e} f: {f}"); // Covariance (object c, object d) g = F(); // Implicit conversion (double x, double y) t = G(); } public static (string a, string b) F() => ("A", "B"); public static (int x, int y) G() => (0, 1); } public class C { public String A = "A"; public String B = "B"; public void Deconstruct(out String a, out String b) { a = A; b = B; } } 

1 The C # team may not be smarter than everyone, but I never lost money, becoming at least as smart as I am.

+8
c # valuetuple
source share
3 answers

The ability of deconstruction to act as implicit converters is what was suggested (by me, therefore I am biased here) before C # 7 was released. The response from the team was (as I read it anyway) that he was asked too close to the release of C # 7, and he took too long to implement, so he was not considered. Since it will now be a devastating change, this is not what will ever happen.

See "Allow Deconstructing and the Implicit Operator for both deconstruction support and conversion to tuple types ." The issue of reposition roslyn for the actual discussion of the case.

+5
source share

(string a, string b) ab declares one tuple type variable (string a, string b) named ab . This allows you to write ab.a or ab.b , but not a or b .

(string a, string b) f = c; tries to convert an unrelated type C to this type of tuple. If you do not write the cast, this will not work.

In particular, as the name implies, destructuring allows you to assign variables; this does not allow you to convert to an unrelated type.

+5
source share

Here is one way to achieve what you are trying to do: in the code example, instead of (string a, string b) f = c; use (string a, string b) f = (_, _) = c; .

You can also write a user-defined conversion from your type to the desired type of tuple.

+3
source share

All Articles