我在理解"Get-Member“定义列时遇到了问题。我在做:
$Array = "ans", "zwei","drei"不出所料,$Array.GetType()回馈了BaseType=System.Array
然后:
$Array | gm 没有说明方法Add() -这是正确的,因为$Array是一个数组。
但是:
gm -inputobject $Array 正在向我展示一个Add()-Method,其定义为
int IList.Add(System.Object value).当然:$Array.Add("vier")不能工作。
我知道: IList是一个接口等等,但是它在这里是完全错误的,因为我们讨论的是一个数组类型的变量?
为了让混乱变得完美:我的ISE的智能感知(PS版本: 4)也显示了Add()-Method。
啊!怎么这么乱呀。如何使用Get-Member正确理解"definition“列?
发布于 2015-06-22 18:41:58
此对象的类型:
$Array = "ans","zwei","drei"如果不是System.Array,而是Object[] -一种直接从System.Array继承的集合类型,但与不同。
如果您深入研究一下,就会发现$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

要获取数组对象本身的成员,而不是数组元素的成员,必须通过-InputObject方法将其传递给Get-Member:
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...
...发布于 2015-06-22 18:39:17
诀窍是$array | get-member返回一个System.String作为类型,在本例中,该字符串没有"Add“方法。如果你的数组等于,比如说@(1,2),你会得到System.Int32的输出作为“它的”类型。这样做的原因是,您使用的管道旨在将数组展开为cmdlet,这些cmdlet通常被设计为对每个输入成员执行一个操作。因此,get-member -InputObject $array 是查询成员数组的正确方式,而不是查询其成员的成员。
$array.Add('vier')的诀窍有点不同--我刚刚测试了一下,异常没有说“非法调用”,它说“大小是固定的”,确实是这样,$array.IsFixedSize返回true。这样做的可能原因是不公开实际的IList更改机制,只将它们声明为“固定大小”,并且仅在设计为接受数组的运算符或方法中覆盖此限制。
更新:正如@Mathias在他的回答中所说,$array的实际类型是System.Object[],而根据它的接口列表,它被设计为对接口上的.NET方法声明自己为“只读”,所以它应该只被Powershell代码修改,而不是.NET代码。
发布于 2015-06-22 19:12:49
首先:当通过管道传递集合时,会枚举集合,因此在本例中,$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'. It is true,Class1和Class2都没有Method方法。所以问题是:如果类显式地实现了接口方法,如何调用它呢?
在PowerShell v3中,情况发生了变化。所有接口方法现在也报告为object的成员,因此调用(New-Object Class2).Method() works。问题是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 5https://stackoverflow.com/questions/30977471
复制相似问题