当前位置:  开发笔记 > 程序员 > 正文

PowerShell:修改数组元素

如何解决《PowerShell:修改数组元素》经验,为你挑选了1个好方法。

我的cmdlet get-objects返回一个MyObject包含公共属性的数组:

public class MyObject{
    public string testString = "test";
}

我希望没有编程技能的用户能够testString从数组的所有对象修改公共属性(如本示例中所示).然后将修改后的数组提供给我的第二个cmdlet,该cmdlet将对象保存到数据库中.

这意味着"编辑代码"的语法必须尽可能简单.

它应该看起来像这样:

> get-objects | foreach{$_.testString = "newValue"} | set-objects

我知道这是不可能的,因为$ _只返回数组中元素的副本.

因此,您需要在循环中通过索引访问元素,然后修改属性.对于不熟悉编程的人来说,这真的很快变得非常复杂.


这样做有"用户友好"的内置方式吗?它不应该比简单更"复杂"foreach {property = value}



1> Mathias R. J..:

我知道这是不可能的,因为$ _只返回数组中元素的副本(https://social.technet.microsoft.com/forums/scriptcenter/en-US/a0a92149-d257-4751-8c2c- 4c1622e78aa2/powershell-modification-array-elements)

我认为你错误地解释了那个话题中的答案.

$_确实是您当前正在迭代的任何枚举器返回的值的本地副本 - 但您仍然可以返回该值的修改副本(如注释中所指出的):

Get-Objects | ForEach-Object {
    # modify the current item
    $_.propertyname = "value"
    # drop the modified object back into the pipeline
    $_
} | Set-Objects

在(据称不可能)需要修改存储的对象数组的情况下,您可以使用相同的技术用新值覆盖数组:

PS C:\> $myArray = 1,2,3,4,5
PS C:\> $myArray = $myArray |ForEach-Object {
>>>    $_ *= 10
>>>    $_
>>>}
>>>
PS C:\> $myArray
10
20
30
40
50

这意味着"编辑代码"的语法必须尽可能简单.

值得庆幸的是,PowerShell在内省方面非常强大.您可以实现一个包装函数,将$_;语句添加到循环体的末尾,以防用户忘记:

function Add-PsItem 
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipeline,ValueFromRemainingArguments)]
        [psobject[]]$InputObject,

        [Parameter(Mandatory)]
        [scriptblock]$Process
    )

    begin {

        $InputArray = @()

        # fetch the last statement in the scriptblock
        $EndBlock = $Process.Ast.EndBlock
        $LastStatement = $EndBlock.Statements[-1].Extent.Text.Trim()

        # check if the last statement is `$_`
        if($LastStatement -ne '$_'){
            # if not, add it
            $Process = [scriptblock]::Create('{0};$_' -f $Process.ToString())
        }
    }

    process {
        # collect all the input
        $InputArray += $InputObject
    }

    end {
        # pipe input to foreach-object with the new scriptblock
        $InputArray | ForEach-Object -Process $Process
    }
}

现在用户可以这样做:

Get-Objects | Add-PsItem {$_.testString = "newValue"} | Set-Objects

ValueFromRemainingArguments属性还允许用户将输入作为无界参数值提供:

PS C:\> Add-PsItem { $_ *= 10 } 1 2 3
10
20
30

如果用户不习惯使用管道,这可能会有所帮助

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有