I've tried using the following code to set up a new Dictionary in my Powershell code. I want the Dictionary to use a tuple as the key, and an Arraylist as the value (so that I can add items to the value over time).
# Create dictionary
$mydict = [Collections.Generic.Dictionary[[Tuple[int,int]],Collections.ArrayList]]::new()
# Add an empty Arraylist to a key
$mydict.Add([Tuple]::Create(0,0),[Collections.ArrayList]::new())
# Try to add an item to this new arraylist
$mydict[(0,0)].Add(1)
MethodInvocationException: Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
# And sure enough:
$mydict[(0,0)].IsFixedSize
True
$mydict[(0,0)].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Anyone know why Powershell is ignoring my requests to add ArrayLists as members, and for some reason silently converting the objects to System.Array instead?
Just like you used [Tuple]::Create(0,0)
, i.e explicit creation of a tuple in the .Add()
call, you must use the same in trying to access an entry:
$null = $mydict[[Tuple]::Create(0,0)].Add(1)
The reason that (0,0)
didn't work as a lookup key is that it is of type [object[]]
and PowerShell's index operator ([…]
) by design supports passing an array of indices, whose elements are individually interpreted as indices to look up.
E.g., (1, 2, 3, 4)[1, -1]
yields 2, 4
, i.e. the second (1
) and the last (-1
) element of the input array.
Since the [object[]]
type of (0, 0)
didn't match the actual key type of $mydict
, $mydict
was in effect treated like a single-element array, it was something akin to the intrinsic array indexing of scalar types[1] that kicked in, meaning that both instances of 0
returned the $mydict
dictionary as a whole, implicitly resulting in a two-element array to which the .Add()
method was applied, and - because a .NET array (whose base type is always System.Array
) is of fixed size - the Collection was of a fixed size.
error was emitted.
[1] Note that PowerShell generally treats objects that implement the System.Collections.IDictionary
interface as single objects (scalars) in its pipeline, even though they are enumerable, namely as key-value pairs. However, with a key type that is an implementation of System.Collections.ICollection
other than an array, such as System.Tuple`2
in your case, numeric indices, which on their own do not match such a key type, seemingly treat the dictionary instance like a single-element array when intrinsic indexing is applied, so that even multiple indices can be applied, and each index with value 0
or -1
(to select the one and only "element" from the start or the end) returns the dictionary itself.