Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# 7:How can I deconstruct an object into a single value using a tuple?

Tags:

c#

tuples

c#-7.0

One of the nice new features of C# 7 is the possibility to define deconstructors for classes and assign the deconstructed values directly to a value tuple.

However, in the case that the object is deconstructed into a single value, I can't find a way to assign it to a tuple. Although there is a type for tuples with a single element (ValueTuple<T>), the shorthand syntax using parentheses doesn't work here. The only way I found to access the deconstructor was to call the Deconstruct method directly, but this eliminates its benefit, as I could use any method for this end.

Does anyone know a better way to deconstruct an object into a single value?

Here is my test code:

class TestClass
{
    private string s;
    private int n;
    public TestClass(string s, int n) => (this.s, this.n) = (s, n);
    public void Deconstruct(out string s) => s = this.s;
    public void Deconstruct(out string s, out int n) => (s, n) = (this.s, this.n);
}

static void Main(string[] args)
{
    var testObject = new TestClass("abc", 3);

    var (s1) = testObject; // sytax error (comma expected)
    ValueTuple<string> t = testObject; // error: "no implicit conversion from TestClass to (string)"
    testObject.Deconstruct(out string s2); // this works
    var (s3, n) = testObject; // no problem

    Console.WriteLine($"{s1} {t.Item1} {s2} {s3} {n}");
    Console.ReadKey();
}
like image 559
Helmut D Avatar asked Jul 07 '17 16:07

Helmut D


2 Answers

Although there is a type for tuples with a single element (ValueTuple<T>), the shorthand syntax using parentheses doesn't work here.

That's correct. The tuple syntax only works for tuples of 2 values or more, so the Deconstruct method with only one out parameter is not very useful. (There is even a ValueTuple type for 0 elements)

The shortest solution is to just ignore the 2nd parameter:

var (s1, _) = testObject;

Edit: based on comments, a little clarification.
As of C# 7, _ is no longer a variable in this situation. It is a new feature called 'discard'.
Even if you have multiple out parameters (and even if they are different types) you can ignore any of them with an underscore:

var (s1, _, _, _) = testObject;
like image 190
Dennis_E Avatar answered Oct 05 '22 22:10

Dennis_E


Deconstructions into a single element are not supported in C# 7.0.

It is unclear why you would need such a mechanism, as you can simply access a property or write a conversion operator to achieve the same thing.

Conceptually, a tuple of one element is just that one element (you don't need a tuple to hold it). So there is no tuple syntax (using parentheses notation) to facilitate that (not to mention it would be syntactically ambiguous). The same applies for deconstructions.

Here are the most relevant LDM notes I could find: 2017-03-15 (zero and one element tuples and deconstructions).

It is possible that such deconstruction could become allowed in some future recursive pattern scenarios, but that has not been finalized yet.

like image 45
Julien Couvreur Avatar answered Oct 06 '22 00:10

Julien Couvreur