-
-
Notifications
You must be signed in to change notification settings - Fork 424
Support IReadOnlyDictionary<K, V> #984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support IReadOnlyDictionary<K, V> #984
Conversation
- Add assertion methods for `IReadOnlyDictionary<K, V>`. - Add assertion methods for `Dictionary<K, V>` to resolve overload ambiguity when using a concrete dictionary as it implements both interfaces. Resolves shouldly#834.
This leaves other dictionary types such as ImmutableDictionary out in the cold, which will be noticed. I may do a followup to add an internal declaration of .NET 9's OverloadResolutionPriorityAttribute and use it to help with this, but that only comes into play if you set your langversion to 13 (currently, preview). The only docs I know of for this are the spec itself, https://github.com/dotnet/csharplang/blob/main/proposals/overload-resolution-priority.md. This is how it works: We could also consider removing the IDictionary extension method or moving it to a different namespace. I think these days it should be rare to have a dictionary that does not implement IReadOnlyDictionary. @slang25 @SimonCropp Do you have any thoughts? |
Well, one important issue with moving or removing the extension method is, how do you then assert on something typed as the interface Is it worth hitting ImmutableDictionary at least, or maybe a few more concrete types, or perhaps just wait for irritated feedback to roll in? :D |
Anyone who does hit this issue could declare their own extension method for the dictionary class that we didn't think of, like ImmutableDictionary/ConcurrentDictionary/ReadOnlyDictionary/etc, and simply call the Shouldly extension method after casting to IReadOnlyDictionary. This may not be an obvious workaround, but we could add this to our docs. As a workaround, we could also say "use LangVersion 13 or later, regardless of your target framework." That would work too, once .NET 9 and C# 13 release in November. Another option: We could add the new extension method under @martincostello Would you be able to benefit from this new extension method if it was only available when the test project targets .NET 9? |
I hadn't considered things like
For me that wouldn't be a problem, as the app where I found the need for this extension is going to be running .NET 9 rc.1 next month (assuming no last-minute issues). |
Okay, perhaps we start with using OverloadPriorityAttribute and only making this overload available in .NET 9 (need to add a net9.0 framework target for this), instead of adding overloads for concrete types, and then revisit as needed? |
Sure, I can do that - how do you want to go about that given that the .NET 9 SDK is still pre-release until November? |
As soon as the CI image has a .NET 9 preview version that contains the compiler update to recognize OverloadResolutionPriorityAttribute, we can update our global.json file with minimal hassle, for example to Lines 1 to 7 in 50e0045
Then we need to change the langversion to preview, with a comment that we'll change it to 13 when .NET 9 ships: shouldly/src/Directory.Build.props Line 4 in 50e0045
Then add an additional Then wrap this around the added overload, along with applying #if NET9_0_OR_GREATER |
Ideally we'd choose the earliest preview version that is actually required in order to get the compiler recognition of OverloadResolutionPriorityAttribute. That would help with any contributors to the repo who might already have that older preview installed, as well as being the best chance of all three of these images having at least that preview version or later: shouldly/.github/workflows/CI.yml Line 27 in 50e0045
|
Okay. Through trial and error, I've confirmed that the compiler only starts recognizing OverloadResolutionPriorityAttribute in .NET 9 Preview 7, in spite of the attribute being added to the core libraries in Preview 5. https://github.com/dotnet/core/blob/main/release-notes/9.0/preview/preview7/csharp.md#prioritize-better-overloads-with-overloadresolutionpriority-attribute This means that the global.json version should be |
Why not just use actions/setup-dotnet to install the SDK? IMO that's best practice as it's deterministic and doesn't need to wait on GitHub to install anything. This approach even works for their daily builds from their CI. My question was more geared towards merging - using a preview is trivial, but do you want main using prerelease software? Because otherwise this is unmergeable until November. |
That sounds good too! Glad to know you're familiar already. Yes, main using prerelease SDK is good with me. It's usually a safe bet, and there are options in the event of a rare surprise. |
- Update to .NET 9 preview 7 SDK. - Add .NET 9 TFM. - Update test projects to .NET9. - Update to LangVersion latest.
- Only support `IReadOnlyDictionary<K, V>` for .NET 9 and later. - Use `[OverloadResolutionPriority]` to prefer `IReadOnlyDictionary` to `IDictionary`. - Remove overloads for `Dictionary<K, V>`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff! Thanks for the help. LGTM after reversing the langversion edits.
Use C# 13 for shiny new features like `[OverloadResolutionPriority]`.
Revert project-specific LangVersion changes.
@slang25, do you mind giving this a look and merging? |
@slang25 Next time I remember this PR exists, I'll probably merge it :D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good. I think we should separately update the net5.0
tfm to net8.0
, so that we have a policy of netstandard2.0
+ Current LTS + Current STS for the main package
IReadOnlyDictionary<K, V>
usingnet9.0
and later only so that[OverloadResolutionPriority]
can be used to avoid ambiguity caused by types that implement both dictionary interfaces.Resolves #834.