Расчетное свойство Powershell PSObject на основе другого свойства

Я создаю массив объектов PSObject с вычисленными свойствами. Мне нужно одно свойство, которое рассчитывается на основе другого свойства того же объекта. Как я могу это сделать? Пример - скажем, у меня есть массив строк, таких как a_1, b_2, c_3 и т. Д., И у меня есть функция поиска, которая возвращает что-то на основе первой части этих строк, то есть someLookUpFunction('a') вернет AA с вводом a. Теперь мне нужно свойство в моем объекте, у которого есть это вычисленное "AA" на основе моего свойства "name".

$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» - это только этот блок скрипта. Как мне заставить его принять ценность?


person miguello    schedule 09.12.2020    source источник
comment
Вы можете использовать оператор подвыражения: 'extendedName' = $($name = ($_ -split "_")[0]; someLookUpFunction $name). Вы можете просто использовать $name = ($_ -split "_")[0] перед командой new-object. Тогда ссылка $name внутри.   -  person AdminOfThings    schedule 09.12.2020
comment
В качестве отступления: функции, командлеты, сценарии и внешние программы PowerShell необходимо вызывать как команды оболочки - foo arg1 arg2 - не как методы C # - ~~ foo('arg1', 'arg2'). Если вы используете , для разделения аргументов, вы создадите массив, который функция видит как единственный аргумент. Чтобы предотвратить случайное использование синтаксиса метода, используйте Set-StrictMode -Version 2 или выше, но обратите внимание на другие его эффекты. Дополнительную информацию см. В этом ответе.   -  person mklement0    schedule 09.12.2020


Ответы (2)


Если вам нужно зафиксировать вывод выражения внутри выражения, вы можете использовать оператор подвыражения $().

$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 parametervalue или functionName parametervalue, если включены позиционные параметры. Синтаксис functionName(parametervalue) может иметь непредвиденные последствия. См. этот ответ для более глубокого погружения в синтаксис вызова функций / методов.

Вы не можете получить доступ к свойству name объекта, пока этот объект не был создан.

person AdminOfThings    schedule 09.12.2020
comment
Отлично, спасибо большое! Не был знаком с оператором подвыражения - вот почему мой код не работал. - person miguello; 09.12.2020

В дополнение к AdminOfThings Good Answer вы можете полностью обойти цикл, используя оператор 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] } }

Это может иметь некоторое преимущество в удобочитаемости, но я стараюсь избегать этого в пользу вызова как можно меньшего количества команд.

person Steven    schedule 09.12.2020