With reference to the discussion on #16199, whilst tuples and deconstructions are different things, the need to define two ways of converting from a type to a deconstruction or a tuple respectively, seems an unnecessary overhead.
Take the following code by way of example,
````cs
public class PseudoTuple
{
public PseudoTuple(T1 item1, T2 item2)
{
Item1 = item1;
Item2 = item2;
}
public T1 Item1 { get; }
public T2 Item2 { get; }
public void Deconstruct(out T1 item1, out T2 item2)
{
item1 = Item1;
item2 = Item2;
}
}
...
void F((int, string) tuple) { }
var t = new PseudoTuple
var (x, y) = t; // Deconstruction. Works fine.
F(t); // This line doesn't compile as can't convert PseudoTuple to ValueTuple
F((x, y)); // Creating a tuple from x, y and passing that. Works fine.
Add the following to `PseudoTuple` and all then compiles:
cs
public static implicit operator (T1, T2)(PseudoTuple
(tuple.Item1, tuple.Item2);
It would be useful if both `Deconstruct` and `implicit operator` could be used for both purposes, requiring only one to be defined. So having `public void Deconstruct(out T1 item1, out T2 item2)` **or** `public static implicit operator (T1, T2)(PseudoTuple<T1, T2> tuple)` defined in `PseudoTuple` then the following statements would compile fine:
cs
void F((int, string) tuple) { }
var t = new PseudoTuple
var (x, y) = t;
F(t);
F((x, y));
````
This would have the added advantage that a Deconstruct extension method could be used to allow implicit conversions to tuples for 3rd party types, as extension operators aren't (yet) supported.
Just to clarify, this would go both ways, right?
public class Foo {
public int X { get; } = 123;
public int Y { get; } = 456;
public void Deconstruct(out int x, out int y) {
x = X;
y = Y;
}
}
public class Bar {
public int X { get; } = 123;
public int Y { get; } = 456;
public static implicit operator (int x, int y)(Bar bar) {
return (bar.X, bar.Y);
}
}
// silent conversion to a tuple
var foo = new Foo();
(int x, int y) tuple = foo;
// translated as
var foo = new Foo();
(int x, int y) tuple;
foo.Deconstruct(out tuple.x, out tuple.y);
// silent deconstruction
var bar = new Bar();
var (x, y) = bar;
// translated as
var bar = new Bar();
var (x, y) = (ValueTuple<int,int>)bar;
@HaloFour,
Thanks for that clarification. That is exactly what I was trying to say.
We are not contemplating any further feature work in C# 7. This proposal would be a breaking change from C# 7 (the addition of a conversion may make an otherwise inapplicable method applicable, and better than the candidate selected in a previous version of the language). We are therefore unlikely to do this.
@gafter,
That's unfortunate. Having caught myself out with this just 24 hours after commenting on #16199, I now realise that @mharthoorn is right and that the deconstruction/tuple dichotomy will cause lots of confusion to developers. This suggestion would have been a trivial fix to that confusion.
Oh well, I guess this is another one to add to the long list of things that will have to be fixed via generators, if/when we get them.
@DavidArno No, it would not be a "trivial fix". Deconstruction can be added by extension methods, and conversions cannot. There are good reasons for both.
@gafter
How about
Tuple<string, int> foo = ("", 0);
And vice versa?
Most helpful comment
@DavidArno No, it would not be a "trivial fix". Deconstruction can be added by extension methods, and conversions cannot. There are good reasons for both.