Exceptions in indexers are always quietly ignored for IDictionary<T1,T2>
See original GitHub issueUpdate: As @SeeminglyScience’s states below, ignoring of exceptions seems to be limited to indexing with types that implement IDictionary<T1, T2>
, in which potential exceptions are deliberately avoided with .TryGetValue()
calls.
An argument could be made that this behavior makes sense for the sake of symmetry with PowerShell’s regular, non-generic (ordered) hashtables, which themselves ignore non-existent keys.
It does amount to PowerShell modifying the behavior of .NET types in a non-obvious manner, however.
At least with Set-StrictMode -Version 3
or higher, using an array’s indexer with an out-of-bounds index results in a statement-terminating error.
The docs state with respect to version 3:
Prohibit out of bounds or unresolvable array indexes.
By contrast, other exceptions appear to be quietly ignored, irrespective of the effective Set-StrictMode
setting.
A follow-up question is: should exceptions other than System.IndexOutOfRangeException
and System.Collections.Generic.KeyNotFoundException
always be surfaced?
Other types of exceptions are probably rare, but they do occur; e.g.:
# Note: Called via .Item() instead of indexer syntax ([...]),
# to ensure that the exception surfaces.
# Throws a System.ArgumentException
[Newtonsoft.Json.Linq.JObject]::Parse('{"foo":1}').Item([datetime]::now)
Steps to reproduce
Set-StrictMode -Version 3
# OK - exception (statement-terminating error)
{ (0,1)[2] } | should -Throw -ErrorId System.IndexOutOfRangeException
# Does NOT throw an exception, even though the underlying type does.
# Note: The non-generic [hashtable] type (@{ ... }) does NOT throw an exception,
# but System.Collections.Generic.Dictionary<T, T> does.
{ $dt = [Collections.Generic.Dictionary[string, string]]::new(); $dt['nosuch'] } |
Should -Throw -ErrorId System.Collections.Generic.KeyNotFoundException
Expected behavior
Both tests should pass.
Actual behavior
The 2nd test fails:
Expected an exception, to be thrown, but no exception was thrown.
That is, the exception that occurs in the [System.Collections.Generic.Dictionary]
indexer is quietly ignored.
You can surface it if you call the underlying .Item()
method (parameterized property) directly:
$dt = [Collections.Generic.Dictionary[string, string]]::new(); $dt.Item('nosuch')
This reports the following error (ultimately a System.Collections.Generic.KeyNotFoundException
exception):
Exception getting "Item": "The given key 'nosuch' was not present in the dictionary"
Environment data
PowerShell Core 7.0.0-preview.4
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (5 by maintainers)
@mklement0
Dictionary<,>
does though:Yeah
IDictionary<,>
follows a different pattern, it doesTryGetValue
instead:https://github.com/PowerShell/PowerShell/blob/d8eca6a729a94c626bc161f94c4e694451d7e4da/src/System.Management.Automation/engine/runtime/Binding/Binders.cs#L4130-L4137
Apparently
JObject
is alsoIDictionary<,>
.