PowerShell了解Get-Member

时间:2015-06-22 10:19:44

标签: powershell

我在理解“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() - 方法。

真是一团糟。如何使用Get-Member正确理解“定义”列?

3 个答案:

答案 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

enter image description here

要获取数组对象本身的成员而不是数组元素的成员,必须通过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接口,单维零基数组也实现该接口的通用版本。一些接口方法是明确实现的,如AddContains

考虑以下代码:

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也不是Class2Method方法。所以问题是:如果类明确地实现它,如何调用接口方法?

在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