51

JavaScript has a nifty feature where you can assign several variables from properties in an object using one concise line. It's called destructuring assignment syntax which was added in ES6.

// New object
var o = {p1:'foo', p2:'bar', p3: 'baz'};
// Destructure
var {p1, p2} = o;
// Use the variables...
console.log(p1.toUpperCase()); // FOO
console.log(p2.toUpperCase()); // BAR

I want to do something similar with C#.

// New anonymous object
var o = new {p1="foo", p2="bar", p3="baz"};
// Destructure (wrong syntax as of C#6)
var {p1, p2} = o;
// Use the variables...
Console.WriteLine(p1.ToUpper()); // FOO
Console.WriteLine(p2.ToUpper()); // BAR

Is there a syntax to do this in C#?

styfle
  • 22,361
  • 27
  • 86
  • 128
  • what scenario required this feature, just curious! – TechnicalSmile Jun 24 '20 at 14:47
  • 1
    @TechnicalSmile There is no requirement for this language feature (or any language feature for that matter). It's all syntactic sugar on top of zeros and ones :) In this case, I want to write less code and this is a feature that enables it. – styfle Apr 20 '21 at 16:21

4 Answers4

33

Closest thing which could help you are Tuples.

C#7 maybe will have something like this:

public (int sum, int count) Tally(IEnumerable<int> values) 
{
    var res = (sum: 0, count: 0); // infer tuple type from names and values
    foreach (var value in values) { res.sum += value; res.count++; }
    return res;
}


(var sum, var count) = Tally(myValues); // deconstruct result
Console.WriteLine($"Sum: {sum}, count: {count}"); 

Link to discussion

Right now it is not possible.

Szer
  • 3,426
  • 3
  • 16
  • 36
  • 3
    See also [the proposed feature](https://github.com/dotnet/roslyn/blob/future/docs/features/patterns.md#user-content-destructuring-assignment) – Lucas Trzesniewski Mar 02 '16 at 17:32
  • 1
    See updated link to [the proposed feature](https://github.com/dotnet/roslyn/blob/features/patterns/docs/features/patterns.md#destructuring-assignment) – styfle Mar 09 '17 at 16:45
  • 4
    Yup, C# 7.0 supports deconstruction: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/#user-content-deconstruction – paulie4 May 10 '17 at 21:57
  • 1
    Tuples are the correct way to do this now that C#7 is here. In fact, I would even say that going forward, you should completely replace anonymous types with tuples because of the more elegant syntax. If your type has more properties than tuples support, you should be making a quick little class anyway. – NH. Apr 02 '18 at 19:24
27

C# 7 Using Tuples. You can achieve something like this.

You can construct and destruct a Tuple. Snippet

var payLoad = (
    Username: "MHamzaRajput",
    Password: "password",
    Domain: "www.xyz.com",
    Age: "24" 
);

// Hint: You just need to follow the sequence. 

var (Username, Password, Domain, Age) = payLoad;
// or
var (username, password, _, _) = payLoad;

Console.WriteLine($"Username: {username} and Password: {password}"); 

Output

Username: MHamzaRajput and Password: password
M. Hamza Rajput
  • 7,810
  • 2
  • 41
  • 36
5

The positional syntax for records comes with deconstruction by default (dotnet fiddle):

public record Person(string firstName, string lastName) {}

var person = new Person("Kyle", "Mit");
var (firstName, lastName) = person;
Console.WriteLine(firstName); // "Kyle"

Looking at the generated code via SharpLab, it just implements a regular Deconstruct method that you could add to your own type if you weren't using records:

[CompilerGenerated]
public void Deconstruct(out string firstName, out string lastName)
{
    firstName = this.firstName;
    lastName = this.lastName;
}

According to the docs on Deconstruction

C# doesn't offer built-in support for deconstructing non-tuple types other than the record and DictionaryEntry types. However, as the author of a class, a struct, or an interface, you can allow instances of the type to be deconstructed by implementing one or more Deconstruct methods.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
  • 1
    Thanks! I particularly like that you can add `public void Deconstruct` to any class so this best answers the question! (the dotnet fiddle was a nice too so I could confirm it works) – styfle Jan 04 '23 at 18:42
2

I've been looking for something like this for a while now and I came across Deconstructor with Classes. This isn't as elegant of a solution as Javascript gives us, but it can definitely simplify a lot of things if done well.

Below is a small example (I have not run this code). I hope this helps others:

class Animal
{
    public string name;
    public string type;

    public Animal(
            string name, 
            string type
        )
    {
        this.name = name;
        this.type = type;
    }

    // Use out params with a 
    // method called Deconstruct
    public void Deconstruct(
            out string name, 
            out string type
        )
    {
        name = this.name;
        type = this.type;
    }
}

class Shelter
{
    public Animal[] animals;
    public int animalCapacity;
    public int numberOfAnimalsInShelter = 0;

    public Shelter(
            int animalCapacity
        )
    {
        this.animalCapacity = animalCapacity;
        animals = new Animal[animalCapacity];
    }

    public void AddAnimalToShelter(
            Animal animal
        )
    {
        animals[numberOfAnimalsInShelter] = animal;
        numberOfAnimalsInShelter++;
    }

    public void AnimalsInShelter()
    {
        for (int i = 0; i < animals.Length; i++)
            {
            // Here is how to use the Deconstructor 
            // method from the Animal class
                var (name, type) = animals[i];
                Console.WriteLine(name);
                Console.WriteLine(type);
            }
    }
}

Output should be the name and type for every animal that gets added to the shelter.

  • Records does have seamless Deconstruct https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#deconstructor-behavior-in-derived-records – Martheen Aug 01 '22 at 17:48