-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[API Proposal]: Dictionary<TKey, TValue>.KeysCollection.Contains #75936
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsBackground and motivation
Dictionary<TKey, TValue> d = ...;
...
if (d.Keys.Contains(...)) { ... } you end up invoking API Proposalnamespace System.Collections.Generic;
public class Dictionary<TKey, TValue>
{
public sealed class KeyCollection
{
- bool ICollection<TKey>.Contains(TKey item)
+ public bool Contains(TKey item);
}
} API Usageif (dictionary.Keys.Contains(...)) Alternative DesignsNo response RisksNo response
|
SGTM |
Shouldn't we encourage calling |
We do; there's an analyzer that does exactly that (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1841). Doesn't mean we shouldn't fix Contains as well, especially when all it takes to fix it is changing its visibility. |
I guess originally it was made private intentionally to prevent people from calling it, but later LINQ came... |
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABAJgEYBYAKGIAYACY8lAbhvqfIDoAZASwB2AR3bUOAZiakGAYQYBvGgxVMpxFAwCy5ABQARfmAz8Ig7FACeAHiEY0DOwD4GAEyMBKBgF4X7sNwA0jCWuNyyZhjYQri65B5iqgzKqsTqmlqkBkYmZhY2dg7Obp4+Lrq6AJIRADY1MMamgraCGE4e/kEhuB7hkdGCsfFiAL40QA |
What is your objection to making the existing method (that's there and that has to be there) just be public? Today (.NET 7) they are not the same: [Benchmark(Baseline = true)]
public bool Contains1() => _dict.Keys.Contains(42);
[Benchmark]
public bool Contains2() => ((ICollection<int>)_dict.Keys).Contains(42);
and even if in the future it could make them the same there are still downsides, such as having to carry around System.Linq.dll and load it even if it's not otherwise needed, not being able to trim it out of an app if it's not otherwise needed, having the JIT have to do more work to inline Enumerable.Contains in order to optimize it away, and so on. |
In Intellisense, the extension method |
We already have such a signal: we have an analyzer that's on by default (info/suggestion) that tells you explicitly to use ContainsKey instead. If this were expensive, I'd agree with you. But this costs almost nothing to fix. Our conversation is already more investment than making the change would cost. It's not even a new method; the method already exists, and has to exist in support of the interface. |
namespace System.Collections.Generic;
public class Dictionary<TKey, TValue>
{
public sealed class KeyCollection
{
- bool ICollection<TKey>.Contains(TKey item)
+ public bool Contains(TKey item);
}
}
public class SortedDictionary<TKey, TValue>
{
public sealed class KeyCollection
{
- bool ICollection<TKey>.Contains(TKey item)
+ public bool Contains(TKey item);
}
} |
@terrajobst are we making the change to ReadOnlyDictionary, SortedDictionary or both? |
Background and motivation
Dictionary<TKey, TValue>.Keys
returns aDictionary<TKey, TValue>.KeysCollection
. This type implementsICollection<TKey>
and has an efficient implementation ofICollection<TKey>.Contains
... but it's explicitly implemented. That means if you do:you end up invoking
Enumerable.Contains
. This does a dynamic check for ICollection and delegates to it, but that's still unnecessary overhead. We can easily fix this by makingKeysCollection.Contains
public / implicitly implemented.API Proposal
API Usage
Alternative Designs
No response
Risks
No response
The text was updated successfully, but these errors were encountered: