Hi there,
in powershell v7 (I think) I found an issue with Arraylists. When I create an arraylist and then destroy it after conversation, it throws an exception. I think this is a bug, isnt it?
Thanks,
Alex
$myAl = New-Object System.Collections.ArrayList
$myAl.Add('15')
[array]$myAl = $myAl
$myAl = $null
$myAl = New-Object System.Collections.ArrayList
$myAl.Add('15')
Exception:
MethodInvocationException:
Line |
6 | $myAl.Add('15')
| ~~~
| Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
Hmm... nah, this is expected behaviour. 馃檪
So, when you declare a variable with the type cast on the left like this:
[array]$myVar = 1
That type cast is recorded as an attribute against the variable itself, and will persist until a new type cast is declared, or you remove the variable explicitly with Remove-Variable
.
Any new value you set to that variable will automatically be cast to that type (or an error will be reported if there is no cast possible).
Your ArrayList is only arraylist until it hits that variable which you're defining to be a simple array. Once it's an array, it's a fixed-size collection and cannot be modified.
@vexx32 your explanation is right but $myAl has add
method and it does not work
,$myAl | gm
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Add Method int IList.Add(System.Object value)
Address Method System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a...
Clear Method void IList.Clear()
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
CompareTo Method int IStructuralComparable.CompareTo(System.Object other, System.Collections.ICo...
Contains Method bool IList.Contains(System.Object value)
CopyTo Method void CopyTo(array array, int index), void CopyTo(array array, long index), void...
Equals Method bool Equals(System.Object obj), bool IStructuralEquatable.Equals(System.Object ...
GetEnumerator Method System.Collections.IEnumerator GetEnumerator(), System.Collections.IEnumerator ...
GetHashCode Method int GetHashCode(), int IStructuralEquatable.GetHashCode(System.Collections.IEqu...
GetLength Method int GetLength(int dimension)
GetLongLength Method long GetLongLength(int dimension)
GetLowerBound Method int GetLowerBound(int dimension)
GetType Method type GetType()
GetUpperBound Method int GetUpperBound(int dimension)
GetValue Method System.Object GetValue(Params int[] indices), System.Object GetValue(int index)...
IndexOf Method int IList.IndexOf(System.Object value)
Initialize Method void Initialize()
Insert Method void IList.Insert(int index, System.Object value)
Remove Method void IList.Remove(System.Object value)
RemoveAt Method void IList.RemoveAt(int index)
Set Method void Set(int , System.Object )
SetValue Method void SetValue(System.Object value, int index), void SetValue(System.Object valu...
ToString Method string ToString()
Item ParameterizedProperty System.Object IList.Item(int index) {get;set;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Length Property int Length {get;}
LongLength Property long LongLength {get;}
Rank Property int Rank {get;}
SyncRoot Property System.Object SyncRoot {get;}
We're getting much more into .NET territory here than what PowerShell has any control over, but to explain somewhat...
System.Array
(which is the base class for System.Object[]
as well as every other type that is a basic array) implements the IList
interfaces which, among other things, demands that it provides an Add()
method. So it does, to comply with the interface. However, the interface only states it has to support the method, not that the method needs to _work_.
There's another IList member that it implements, you'll note that there's an IsFixedSize
member property in your Get-Member result there; the expectation is that if IsFixedSize
is true
, the Add()
and similar methods are expected to throw / error out instead of doing something to the list.
Adding onto what @vexx32 said, IList.Add
is an explicit interface implementation. PowerShell doesn't surface this distinction very well, but in C# that method can't be used unless you are explicitly casting the array as IList
object[] myArray = new object[0];
// Compiles
((IList)myArray).Add(0);
// Doesn't compile
myArray.Add(0);
but some other methods like IList.Clear
, IList.IndexOf
work and it gets confused.
@scriptingstudio Yeah Clear
works because it's of a fixed size, not read only (it doesn't change the size of the array, it just null
s out every item). Why wouldn't IndexOf
work?
I would suggest that inactive methods should be hidden.
It's not inactive, it throws by design. There's no way for PowerShell to determine that.
I get the frustration, I really do. When I first ran into this I was incredibly confused by it. Sometimes design patterns that make a lot of sense in C# are going to be surfaced in PowerShell in a really unavoidably bad way, there's not much that can really be done about it. I wish when they were initially designing the binder they required a cast to access explicitly implemented members, but they already didn't do that. Unfortunately if they changed it to work like that now it would be a pretty large breaking change.
Thank you guys for all your patient support and explanations.
this code Works
```$myAl = New-Object System.Collections.ArrayList
$myAl.Add('15')
[array]$myAl = $myAl
Remove-Variable myAl
$myAl = New-Object System.Collections.ArrayList
$myAl.Add('15')
Most helpful comment
We're getting much more into .NET territory here than what PowerShell has any control over, but to explain somewhat...
System.Array
(which is the base class forSystem.Object[]
as well as every other type that is a basic array) implements theIList
interfaces which, among other things, demands that it provides anAdd()
method. So it does, to comply with the interface. However, the interface only states it has to support the method, not that the method needs to _work_.There's another IList member that it implements, you'll note that there's an
IsFixedSize
member property in your Get-Member result there; the expectation is that ifIsFixedSize
istrue
, theAdd()
and similar methods are expected to throw / error out instead of doing something to the list.