Closed skrysmanski closed 8 months ago
Tagging @buyaa-n @CollinAlpert
Similar to https://github.com/dotnet/runtime/issues/97293. Moving to dotnet\runtime for triage
Tagging subscribers to this area: @dotnet/area-system-collections See info in area-owners.md if you want to be subscribed.
Author: | skrysmanski |
---|---|
Assignees: | - |
Labels: | `area-System.Collections` |
Milestone: | - |
@mavasani Just out of curiosity: Why was this issue moved to the runtime repo?
Now, the CA rule suggests that the developer removes the
Contains()
call - which will result in a guaranteedNotSupportedException
ifMyList
is aReadOnlyCollection
The CA rule is correct in that Remove
is meant never to throw based on a presence precondition, but to return true
or false
depending on whether the value was successfully removed. It should not be gated on a Contains
call.
In order to avoid calling mutating operations on a read-only collection type, you should check the value of the IsReadOnly
property. It's defined on ICollection<T>
for exactly this reason.
The rule's name is currently "Unnecessary call to 'Contains' for sets" which apparently is no longer true because the rule now also checks for
IList
.
The name aside, the description of the rule states that it looks for ICollection<T>.Remove
.
I think the concern of a collection being read-only is orthogonal to this analyzer -- the example would throw an exception regardless of whether its recommendation has been applied.
Side note: The rule's name is currently "Unnecessary call to 'Contains' for sets" which apparently is no longer true because the rule now also checks for IList.
Perhaps the title could be improved, however the documentation for the analyzer does state that it applies to ICollection<T>
types as well.
@chrisoverzero
The CA rule is correct in that Remove is meant never to throw based on a presence precondition, but to return true or false depending on whether the value was successfully removed.
Maybe I misunderstood you but that's exactly what ReadOnlyCollection.Remove()
does - it throws an exception.
@eiriktsarpalis
I think the concern of a collection being read-only is orthogonal to this analyzer -- the example would throw an exception regardless of whether its recommendation has been applied.
The original code would not throw an exception if the value wasn't present in the list - whereas the "fixed" code throws an exception in this case.
@skrysmanski It does throw, but not based on a presence precondition.
The original code would not throw an exception if the value wasn't present in the list - whereas the "fixed" code throws an exception in this case.
But it still throws if it isn't. It cannot be claimed that the original implementation was correct and that the fixer broke it.
Analyzer
Diagnostic ID: CA1868
Describe the improvement
The rule CA1868 currently creates a (dangerous) suggestion in our code. Reason: Some
ICollection<T>
implementations throw aNotSupportedException
inRemove()
- for exampleReadOnlyCollection<T>
.We have basically this code:
Now, the CA rule suggests that the developer removes the
Contains()
call - which will result in a guaranteedNotSupportedException
ifMyList
is aReadOnlyCollection
(which was done most likely because of CA1002).While, in my opinion, our code is... sub-optimal, it's unfortunately a public API which we can't change (easily).
So, at good compromise for us would be to restrict this rule - via an option - to only concrete types (e.g.
List<T>
).Side note: The rule's name is currently "Unnecessary call to 'Contains' for sets" which apparently is no longer true because the rule now also checks for
IList
.