【问题标题】:Make PowerShell think an object is not enumerable让 PowerShell 认为一个对象是不可枚举的
【发布时间】:2011-04-25 11:55:51
【问题描述】:

我一直在研究一些 PowerShell 函数来管理在我们创建的程序集中实现的对象。我一直在使用的类之一实现了 IEnumerable。不幸的是,这会导致 PowerShell 一有机会就展开对象。 (我无法改变该类实现 IEnumerable 的事实。)

我通过创建一个 PSObject 并将自定义对象的属性复制到 PSObject,然后返回它而不是自定义对象来解决此问题。但我真的更愿意返回我们的自定义对象。

有没有办法,大概是使用我的 types.ps1xml 文件,从 PowerShell 隐藏这个类的 GetEnumerator() 方法(或者告诉 PowerShell 永远不要展开它)。

【问题讨论】:

  • 所以你有一个自定义的集合类,你不希望 powershell 把它当作一个集合?
  • 是的,差不多就是这样。除了集合之外,该类还有其他东西。请不要让这演变成关于这个类是否应该是可枚举的(缺点)优点的讨论。

标签: powershell


【解决方案1】:

包裹在PSObject 中可能是最好的方法。

您也可以将其显式包装在另一个集合中 - PowerShell 仅展开一层。

此外,在 C#/VB/... 中编写 cmdlet 时,当您调用 WriteObject 时,请使用带有第二个参数的重载:如果为 false,则 PowerShell 不会枚举作为第一个参数传递的对象。

【讨论】:

    【解决方案2】:

    查看 Write-Output 替换 http://poshcode.org/2300,它有一个 -AsCollection 参数,可让您避免展开。但基本上,如果您正在编写一个输出集合的函数,并且您不希望该集合展开,则需要使用 CmdletBinding 和 PSCmdlet:

    function Get-Array {
        [CmdletBinding()]
        Param([Switch]$AsCollection) 
    
        [String[]]$data = "one","two","three","four"
        if($AsCollection) {
            $PSCmdlet.WriteObject($data,$false)
        } else {
            Write-Output $data
        }
    }
    

    如果你用 -AsCollection 调用它,你会得到非常不同的结果,尽管它们在控制台中看起来是一样的。

    C:\PS> Get-Array 
    
    one
    two
    three
    four
    
    C:\PS> Get-Array -AsCollection
    
    one
    two
    three
    four
    
    C:\PS> Get-Array -AsCollection| % { $_.GetType() }
    
    
    IsPublic IsSerial Name       BaseType                             
    -------- -------- ----       --------                             
    True     True     String[]   System.Array                         
    
    
    
    C:\PS> Get-Array | % { $_.GetType() }
    
    
    IsPublic IsSerial Name       BaseType                             
    -------- -------- ----       --------                             
    True     True     String     System.Object                        
    True     True     String     System.Object                        
    True     True     String     System.Object                        
    True     True     String     System.Object   
    

    【讨论】:

    • 问题是我想避免让它永远展开。我可以从我的函数中返回对象,而无需使用 return-as-array 技巧(或您所描述的)展开它。但最终我会意外地展开它。
    • 简单地说:我知道没有办法做到这一点,但请不要尝试:) ...如果你找到了一种方法,你最终会导致一堆错误报告人们无法弄清楚为什么您的收藏中没有任何内容,即使 .Count 报告了一个不错的大数字。
    【解决方案3】:

    这可能不会直接回答原始问题,因为它在技术上并没有返回自定义对象本身,但我有一个类似的问题,我试图显示实现 IEnumerable 的自定义类型的属性并认为它值得分享。将此对象通过管道传输到 Get-MemberSelect-Object 等 cmdlet 中始终会枚举集合的内容。但是,直接使用这些 cmdlet 并将对象传递给 -InputObject 参数会产生预期的结果。在这里,我以ArrayList 为例,但$list 可以是您的自定义集合类型的实例:

    # Get a reference to a collection instance
    $list = [System.Collections.ArrayList]@(1,2,3)
    
    # Display the properties of the collection (in this case, the ArrayList),
    # not the items it contains (Int32)
    Select-Object -InputObject $list -Property *
    
    # List the members of the ArrayList class, not the contained items
    Get-Member -InputObject $list
    

    正如其他cmets所说,你可以将Select-Object的结果保存为变量,创建一个新的PSObject可以直接使用而不用枚举内容:

    # Wrap the collection in a PSObject
    $obj = Select-Object -InputObject $list -Property *
    
    # Properties are displayed without enumerating contents
    $obj
    $obj | Format-List
    $obj | Format-Table
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多