Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to reconstruct a tuple to a compatible class?

Tags:

c#

.net

c#-7.0

Given a tuple (int, string) v and a class C { int, string }, in C#7, implementing C's Deconstruct(out int k, out string v) would allow the ff.:

C c = new C();
(int k, string v) = c;

But the reverse seems unsupported, such that the tuple can be "reconstructed" to a compatible class:

(int k, string v) vt = (1, "one");
C c = vt;

I'm thinking it should be supported if C has a constructor that "matches" C's Deconstruct() parameters:

class C
{
    public C(int k, string v)
    ...
}

Is it possible? Available? Planned? I can't seem to find anything about it. Or perhaps a re-usable code/trick to "Reconstruct"?

like image 975
Edmundo Mendiola Avatar asked Jul 14 '17 10:07

Edmundo Mendiola


3 Answers

Of course you can. Simply implement an implicit operator:

public static implicit operator C((int, string) t) 
    => new C(t.Item1, t.Item2);

There is no need of some special Reconstruct method because the language already provides the necessary tools to achieve the behavior you want.

like image 154
InBetween Avatar answered Nov 02 '22 05:11

InBetween


There is a very subtle distinction between:

(int, string) x = c; // tuple assignment
(int a, string b) x = c; // tuple assignment with member aliases

and

(int a, string b) = c; // deconstruction

Importantly your code is neither of these, so won't compile - but from the context it is clear that you're talking about deconstruction syntax, so I'm assuming the bottom form.

The deconstruction syntax (the one without a name after the tuple-like expression) doesn't actually create a tuple. In fact, it requires names in the pair:

(int a, string b) = c;

or:

var (a, b) = c;

This is not a tuple, but is convenience syntax for:

c.Deconstruct(out int a, out string b);

So: at no point are tuples involved (although oddly the System.ValueTuple reference is still required).

The reverse operation - passing multiple variables into a constructor - is: a regular constructor. Note that you couldn't pass the "tuple-like thing" anywhere, because it doesn't have a name - it isn't a local.

like image 26
Marc Gravell Avatar answered Nov 02 '22 06:11

Marc Gravell


There is already a way to do the opposite of deconstructing (ie. taking some object apart to its component elements). It is "constructing" (ie. making an object from components). The most straightforward way to do the opposite of (x, y) = c; is to do c = new C(x, y);.

There is a candidate feature that is being considered to simplify syntax like c = new C(x, y); down to c = new (x, y); by omitting/inferring the type of the constructor. It's called target-typed construction ([1]).

If you want to propose some other way of constructing, it would be important to show the value of the new feature. The csharplang repo is a good place to discuss such ideas and get a feel for the community and the team's feedback.

Removing the new may be discussed, but I don't think it's a good idea. For instance, in (x, y, z) = (a, b); should the compiler consider constructing a type C from two elements a and b, then invoking the Deconstruct method with three elements that it may find on C? You can see how treating deconstructions as conversions (that can chain and appear in a number of places in the code) leads to combinatorial explosion.

[1]: https://github.com/dotnet/csharplang/issues/100 (the link tracks this candidate feature and has a link to most recent LDM notes, which are succinct as the language feature was not discussed in details).

like image 32
Julien Couvreur Avatar answered Nov 02 '22 06:11

Julien Couvreur