Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

ILookup<TKey, TElement> does not round trip properly for missing keys #1431

Copy link
Copy link

Description

@joelverhagen
Issue body actions

Bug description

In System.Linq the default ILookup<TKey, TElement> implementation returns an empty sequence when the provided key does not exist, per https://docs.microsoft.com/en-us/dotnet/api/system.linq.lookup-2.item?view=net-6.0#remarks.

However, when you roundtrip an ILookup<TKey, TElement> through MessagePack you end up with an instance that throws a KeyNotFoundException when the key does not exist.

Repro steps

using MessagePack;

var lookup = new[] { "foo" }.ToLookup(x => x);
var mc = new MyClass { Lookup = lookup };
byte[] bytes = MessagePackSerializer.Serialize(mc);
MyClass mc2 = MessagePackSerializer.Deserialize<MyClass>(bytes);

Console.WriteLine("Original: " + mc.Lookup["bar"].Count());
Console.WriteLine("Deserialized: " + mc2.Lookup["bar"].Count());

[MessagePackObject]
public class MyClass
{
    [Key(0)]
    public ILookup<string, string> Lookup { get; set; }
}

Expected behavior

This repro program should show:

Original: 0
Deserialized: 0

Actual behavior

Instead, it shows:

Original: 0
Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'bar' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at MessagePack.Formatters.Lookup`2.get_Item(TKey key)
   at Program.<Main>$(String[] args) in C:\Users\joelv\Desktop\MessagePackRepro\MessagePackRepro\Program.cs:line 9

C:\Users\joelv\Desktop\MessagePackRepro\MessagePackRepro\bin\Debug\net6.0\MessagePackRepro.exe (process 39896) exited with code -532462766.
  • Version used: 2.3.85
  • Runtime: .NET 6

Additional context

You can do a workaround with Contains but this requires two lookups.

using MessagePack;

var lookup = new[] { "foo" }.ToLookup(x => x);
var mc = new MyClass { Lookup = lookup };
byte[] bytes = MessagePackSerializer.Serialize(mc);
MyClass mc2 = MessagePackSerializer.Deserialize<MyClass>(bytes);

Console.WriteLine("Original: " + mc.Lookup["bar"].Count());
Console.WriteLine("Deserialized: " + (!mc2.Lookup.Contains("bar") ? 0 : mc2.Lookup["bar"].Count()));

[MessagePackObject]
public class MyClass
{
    [Key(0)]
    public ILookup<string, string> Lookup { get; set; }
}
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.