96

Is it possible in C#7 to use deconstruction in a foreach-loop over a Dictionary? Something like this:

var dic = new Dictionary<string, int>{ ["Bob"] = 32, ["Alice"] = 17 }; foreach (var (name, age) in dic) { Console.WriteLine($"{name} is {age} years old."); } 

It doesn't seem to work with Visual Studio 2017 RC4 and .NET Framework 4.6.2:

error CS1061: 'KeyValuePair' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'KeyValuePair' could be found (are you missing a using directive or an assembly reference?)

1
  • This is still a problem in VS Code 1.61.0 with C# extension 1.23.16. Commented Oct 20, 2021 at 5:33

4 Answers 4

98

If you don't like having to write the Deconstruct method, especially if you only need it in one place, here's how to do it as a one-liner with LINQ:

Using your original dictionary:

var dic = new Dictionary<string, int>{ ["Bob"] = 32, ["Alice"] = 17 }; 

You can do it like this:

foreach (var (name, age) in dic.Select(x => (x.Key, x.Value))) { Console.WriteLine($"{name} is {age} years old."); } 
Sign up to request clarification or add additional context in comments.

2 Comments

this will also work when joining via LINQ, when you end up by having an anon class with one field for each model in the result;
Quick addition (since I just ran into this), this only works if you return a tuple (as in the above answer); if you're returning an anonymous object like x => new { x.Key, x.Value } you'll still get the error about not having a deconstructor!
85

First you have to add an extension method for KeyValuePair:

public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value) { key = tuple.Key; value = tuple.Value; } 

Then you will get a different error:

error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported

According to this answer you have to install the NuGet package System.ValueTuple.

Then it should compile. However Visual Studio 2017 RC4 will say that it cannot resolve the symbol names name and age. They should hopefully fix this in a future update.

6 Comments

Not sure why RC4 is giving you that error. name and age resolve just fine and the code works when I try it.
So static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> is going to be an extension method I'll have to write over and over in each project once VS2017 drops? Wonderful.
@Tinister: Maybe they'll have it implemented for the release next week.
@Tinister, why rewrite it every time? Create a nuget package and import it into your projects...
@Tinister you should already be pushing your own reusable code into your own library
|
54

Deconstruct of KeyValuePair<TKey,TValue> is implemented in .NET Core 2.0, but not in .NET Framework (up to 4.8 preview) unfortunately.

3 Comments

Deconstruct on KeyValuePair will be included into .NET Standard 2.1
That's why some of my projects that target multiple frameworks (including .net-core-2.0) sometimes support it and another time not. I thought I'm loosing my mind.
It works in .NET 5.
0

You can also deconstruct inside the loop. I feel like it's cleaner code than the LINQ solution and I suspect less overhead.

foreach (var kvp in dic) { var (name, age) = (kvp.Key, kvp.Value); Console.WriteLine($"{name} is {age} years old."); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.