Powershell PSObject 基于另一个 属性 计算 属性

Powershell PSObject calculated property based on another property

我正在创建一个具有计算属性的 PSObject 数组。我需要一个 属性 是根据同一对象的 另一个 属性 计算出来的。我怎么做? 示例 - 假设我有字符串数组,如“a_1”、“b_2”、“c_3”等,并且我有一个基于 return 的查找函数在这些字符串的第一部分,即 someLookUpFunction('a') 将 return “AA” 输入“a”。 现在我的对象中需要一个 属性,它根据我的 'name' 属性

计算出 'AA'
$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | ForEach-Object{
  New-Object PSObject -Property @{
     'name' = ($_ -split "_")[0]
     'extendedName' = {$name = ($_ -split "_")[0]; someLookUpFunction($name) }
  }
}

上面的代码部分不起作用,因为 'extendedName' 属性 的输出只是这个脚本块。如何让它取值?

如果需要在表达式中捕获表达式的输出,可以使用子表达式运算符 $().

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | ForEach-Object {
  [pscustomobject]@{
     'name' = ($_ -split "_")[0]
     # You can't reference the name property above in this property because it has not been created yet.
     'extendedName' = $($name = ($_ -split "_")[0]; someLookUpFunction $name)
  }
} 

但是,在您的示例中,这不是必需的。您可以在自定义对象创建之前定义一个变量,然后在对象创建代码中引用它:

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | ForEach-Object {
  $name = ($_ -split '_')[0]
  [pscustomobject]@{
     'name' = $name
     'extendedName' = someLookUpFunction $name
  }
} 

您也可以直接将表达式传递给参数,前提是它可以被正确标记化:

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | ForEach-Object {
  [pscustomobject]@{
     'name' = ($_ -split '_')[0]
     'extendedName' = someLookUpFunction ($_ -split '_')[0]
  }
} 

注意: 如果启用了位置参数,则不使用管道调用函数的正确方法是 functionName -parametername parametervaluefunctionName parametervalue。语法 functionName(parametervalue) 可能会产生意想不到的后果。请参阅 以深入了解 function/method 调用语法。

在对象创建之前,您无法访问该对象的 name 属性。

除了 之外,您还可以使用带有计算的 属性 哈希语法的 select 语句完全绕过循环:

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | 
Select-Object @{Name = 'Name'; Expression = { ($_ -Split '_')[0] } },
    @{Name = 'ExtendedName'; Expression = { SomeLookupFunction ($_ -Split '_')[0] } }

为了不执行 -Split '_' 2x 的效率,如果你确实使用循环,只需使用变量和引用两次。

AdminOfThings 示例的更改版本:

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | ForEach-Object {
  $TmpName = ($_ -split '_')[0]
    [pscustomobject]@{
     'name' = $TmpName
     'extendedName' = someLookUpFunction $TmpName
  }
} 

在 属性 添加到对象之前不能引用它也是正确的。解决这个问题的一种方法是只使用 2 select 语句:

$stringArray = @('a_1', 'b_2', 'c_3')
$objectArray = $stringArray | 
Select-Object @{Name = 'Name'; Expression = { ($_ -Split '_')[0] } } |
Select-Object *, @{Name = 'ExtendedName'; Expression = { SomeLookupFunction ($_ -Split '_')[0] } }

这可能有一些可读性优势,但是,我尽量避免它,以支持调用尽可能少的命令。