13

Can the new feature in C# 7.0 (in VS 2017) to give tuple fields names be translated to KeyValuePairs?

Lets assume I have this:

class Entry
{
  public string SomeProperty { get; set; }
}

var allEntries = new Dictionary<int, List<Entry>>();
// adding some keys with some lists of Entry

It would be nice to do something like:

foreach ((int collectionId, List<Entry> entries) in allEntries)

I have already added System.ValueTuple to the project.

Being able to write it like that would be much better than this traditional style:

foreach (var kvp in allEntries)
{
  int collectionId = kvp.Key;
  List<Entry> entries = kvp.Value;
}
svick
  • 236,525
  • 50
  • 385
  • 514
ZoolWay
  • 5,411
  • 6
  • 42
  • 76
  • Please provide a [mcve]. We don't know what `allEntries` is, which makes it really hard to try to help... – Jon Skeet Apr 07 '17 at 15:54
  • @JonSkeet I added more data about what kind of Dictionary this could be although the question is generic, could be a `Dictionary` as well. – ZoolWay Apr 07 '17 at 16:03
  • 1
    Just the fact that it's a `Dictionary<,>` is a good start - you hadn't mentioned that before. I think it would be simpler if you rewrote the question with a [mcve] using `Dictionary` though. I'll have a look in a bit... – Jon Skeet Apr 07 '17 at 16:05

1 Answers1

20

Deconstruction requires a Deconstruct method defined either on the type itself, or as an extension method. KeyValuePaire<K,V> itself doesn't have a Deconstruct method, so you need to define an extension method:

static class MyExtensions
{
    public static void Deconstruct<K,V>(this KeyValuePair<K,V> kvp, out K key, out V value)
    {
      key=kvp.Key;
      value=kvp.Value;
    }
}

This allows you to write:

var allEntries = new Dictionary<int, List<Entry>>();
foreach(var (key, entries) in allEntries)
{
    ...
}

For example:

var allEntries = new Dictionary<int, List<Entry>>{
    [5]=new List<Entry>{
                        new Entry{SomeProperty="sdf"},
                        new Entry{SomeProperty="sdasdf"}
                        },
    [11]=new List<Entry>{
                        new Entry{SomeProperty="sdfasd"},
                        new Entry{SomeProperty="sdasdfasdf"}
                        },    };
foreach(var (key, entries) in allEntries)
{
    Console.WriteLine(key);
    foreach(var entry in entries)
    {
        Console.WriteLine($"\t{entry.SomeProperty}");
    }
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • 5
    Note that [`KeyValuePair` will have `Deconstruct` in .Net Core 2.0](https://apisof.net/catalog/System.Collections.Generic.KeyValuePair%3CTKey,TValue%3E.Deconstruct(TKey,TValue)) (and likely also some future versions of .Net Standard and .Net Framework). – svick Apr 08 '17 at 20:14
  • Are you sure that works? Isn't `Deconstruct` supposed to allow to deconstruct a type the way you deconstruct a tuple. Not into a tuple. – Paulo Morgado Apr 09 '17 at 22:02
  • The code compiles and runs. Besides, *this* snippet doesn't create a tuple, it deconstructs a KVP into two variables. That's not different than the `Point` example in [What's new in C# 7](https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/). – Panagiotis Kanavos Apr 10 '17 at 07:32
  • I think it is different as the `Point` example calls a method where the out-parameters are declared in the parameter call but here the return value is split. There are similarities, though. But this writing requires an appropiate `Deconstruct`. In this end this is just syntax sugar but I like it. – ZoolWay Apr 10 '17 at 07:46
  • @ZoolWay It's exactly the same code `(var myX, var myY) = GetPoint(); class Point { /* ... */ public void Deconstruct(out int x, out int y) { x = X; y = Y; } }` except the here an extension method is used instead of declaration in the class. – Teejay Sep 24 '18 at 09:29