我在理解“Get-Member”定义列时遇到问题。 我在做:
$Array = "ans", "zwei","drei"
$Array.GetType()
回复 - 正如所料 - BaseType=System.Array
然后:
$Array | gm
对方法Add()
一无所知 - 这是正确的,因为$Array
是一个数组。
可是:
gm -inputobject $Array
向我展示Add()
- 方法,其定义为
int IList.Add(System.Object value).
当然:$Array.Add("vier")
不起作用
我知道:IList是一个接口等,但它完全错了,因为我们讨论的是Array类型的变量?
让混乱变得完美:我的ISE的智能感知(PS版本:4)也显示了Add()
- 方法。
答案 0 :(得分:5)
此对象的类型:
$Array = "ans","zwei","drei"
如果不是 System.Array
,而是Object[]
- 一种直接从System.Array
继承但与...不同的集合。
如果你深入挖掘一下rabbithole,你会发现$Array
的类型确实实现了IList
:
PS C:\> $Array.GetType().ImplementedInterfaces
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ICloneable
True False IList
True False ICollection
True False IEnumerable
True False IStructuralComparable
True False IStructuralEquatable
True False IList`1
True False ICollection`1
True False IEnumerable`1
True False IReadOnlyList`1
True False IReadOnlyCollection`1
$Array | gm
未显示Add()
方法的原因是,当您将$Array
传递给gm
时,管道会尝试枚举$Array
的内容} {以及gm
显示您实际上是所包含类型的成员 - System.String
:
要获取数组对象本身的成员而不是数组元素的成员,必须通过Get-Member
方法将其传递给-InputObject
:
PS C:\> Get-Member -InputObject $Array
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, C...
Clear Method void IList.Clear()
Clone Method System.Object Clone(), System.Object IClonea...
CompareTo Method int IStructuralComparable.CompareTo(System.O...
Contains Method bool IList.Contains(System.Object value)
CopyTo Method void CopyTo(array array, int index), void Co...
Equals Method bool Equals(System.Object obj), bool IStruct...
...
答案 1 :(得分:4)
诀窍是$array | get-member
在这种情况下返回System.String
作为类型,该字符串没有“添加”方法。如果您的数组等于@(1,2)
,那么您将获得System.Int32
的输出作为“其”类型。这样做的原因是您正在使用旨在将阵列展开为cmdlet的管道,这些cmdlet通常用于为每个输入成员执行一个操作。因此,get-member -InputObject $array
是查询成员数组的正确方法,而不是查询 成员的成员。
$array.Add('vier')
的诀窍有点不同 - 我刚刚测试过,例外并没有说“非法通话”,它说“大小是固定的”,确实如此,{{1} }返回true。可能的原因是不公开实际的$array.IsFixedSize
更改机制,只是将它们声明为“固定大小”,并且仅在用于接受数组的运算符或方法中覆盖此限制。
更新:正如@Mathias在他的回答中所说,IList
的实际类型是$array
我错过了,并且通过其界面列表,它被设计为声明自己为“只读” “对于接口上的.NET方法,所以它只能由Powershell代码修改,而不是.NET代码。
答案 2 :(得分:3)
首先:集合在被管道传递时被枚举,因此在这种情况下$Array | gm
Get-Member
cmdlet看不到数组,而是看到它的各个项目,因此它报告的项目成员不是阵列。
第二:数组实现IList
接口,单维零基数组也实现该接口的通用版本。一些接口方法是明确实现的,如Add
或Contains
。
考虑以下代码:
Add-Type -TypeDefinition @'
using System;
public interface IInterface {
void Method();
}
public class Class1:IInterface {
void IInterface.Method() {
throw new NotSupportedException();
}
}
public class Class2:IInterface {
void IInterface.Method() {
//Do something.
}
}
'@
(New-Object Class1).Method()
(New-Object Class2).Method()
([IInterface](New-Object Class1)).Method()
([IInterface](New-Object Class2)).Method()
尝试在PowerShell v2中运行它。所有Method
次调用都失败,错误为Method invocation failed because [Class] doesn't contain a method named 'Method'.
这是正确的,Class1
也不是Class2
有Method
方法。所以问题是:如果类明确地实现它,如何调用接口方法?
在PowerShell v3中发生了变化。所有接口方法现在也报告为对象的成员,因此调用(New-Object Class2).Method()
有效。问题是PowerShell没有办法知道为什么接口方法是显式实现的,因为它不受支持或者因为它打算通过接口调用,所以它必须报告Method
作为Class1
的成员和Class2
,即使Class1
实际上不支持会员。
例如IList.Contains
是有效的数组调用,但是这段代码:
$a=1..10
$a.Contains(5)
在PowerShell v2中失败:
function f{
param(
[Collections.IList]$List,
[Object]$Item
)
$List.Contains($Item)
}
$Array=1..10
$List=New-Object Collections.Generic.List[Object] (,$Array)
f $Array 5 #This will fail in PowerShell v2
f $List 5