我想使用 PowerShell 设置嵌套对象属性的值。当您尝试设置第一级属性的值时,非常简单:
$propertyName = "someProperty"
$obj.$propertyName = "someValue" # ← It works
对于嵌套属性,它不起作用:
$propertyName = "someProperty.someNestedProperty"
$obj.$propertyName = "someValue" # ← It doesn't work and raises an error.
如何使用 PowerShell 通过属性名称设置嵌套对象属性的值?
MCVE
对于那些想要重现问题的人,这里有一个简单的例子:
$Obj= ConvertFrom-Json '{ "A": "x", "B": {"C": "y"} }'
# Or simply create the object:
# $Obj= @{ A = "x"; B = @{C = "y"} }
$Key = "B.C"
$Value = "Some Value"
$Obj.$Key = $Value
运行命令,你会收到一个错误:
“在此对象上找不到属性‘B.C’。请验证 属性存在并且可以设置。”
注意:代码支持任意级别的嵌套。
我创建了
SetValue
和 GetValue
函数,让您可以通过名称动态获取和设置对象(包括 json 对象)的嵌套属性,并且它们工作得很好!
它们是递归函数,通过拆分嵌套属性名称来解析复杂属性并逐步获取嵌套属性。
按名称获取嵌套属性的 GetValue 和 SetValue
# Functions
function GetValue($object, $key)
{
$p1,$p2 = $key.Split(".")
if($p2) { return GetValue -object $object.$p1 -key $p2 }
else { return $object.$p1 }
}
function SetValue($object, $key, $Value)
{
$p1,$p2 = $key.Split(".")
if($p2) { SetValue -object $object.$p1 -key $p2 -Value $Value }
else { $object.$p1 = $Value }
}
示例
在下面的示例中,我使用
B.C
动态设置 SetValue
并使用 GetValue
函数按名称获取其值:
# Example
$Obj = ConvertFrom-Json '{ "A": "x", "B": {"C": "y"} }'
# Or simply create the object:
# $Obj = @{ A = "x"; B = @{C = "y"} }
$Key = "B.C"
$Value = "Changed Dynamically!"
SetValue -object $Obj -key $Key -Value $Value
GetValue -object $Obj -key $Key
您的自己的解决方案是有效的,但不支持索引访问作为嵌套属性访问路径的一部分(例如,
B[1].C
)
一个简单的替代方法是使用 Invoke-Expression
(
iex
)。 虽然它通常应该避免,但在某些特殊情况下它提供了最简单的解决方案,这就是其中之一:
假设您完全控制或隐式信任属性访问字符串:
$obj = ConvertFrom-Json '{ "A": "x", "B": [ {"C": "y"}, { "C": "z"} ] }'
$propPath = 'B[1].C'
# GET
Invoke-Expression "`$obj.$propPath" # -> 'z'
# SET
$value = 'Some Value'
Invoke-Expression "`$obj.$propPath = `$value"
如果您不信任输入,您可以避免不必要的命令注入,如下所示:[1]
$safePropPath = $propPath -replace '`|\$', '`$&'
Invoke-Expression "`$obj.$safePropPath"
# ...
对于安全封装上述功能的便捷功能/ETS方法,请参阅这个答案。
$
字符都转义为
`$
,以防止
Invoke-Expression
将它们视为变量引用或子表达式;同样,预先存在的
`
实例可以通过加倍 来转义。
function GetValue($object, [string[]]$keys)
{
$propertyName = $keys[0]
if($keys.count.Equals(1)){
return $object.$propertyName
}
else {
return GetValue -object $object.$propertyName -key ($keys | Select-Object -Skip 1)
}
}
function SetValue($object, [string[]]$keys, $value)
{
$propertyName = $keys[0]
if($keys.count.Equals(1)) {
$object.$propertyName = $value
}
else {
SetValue -object $object.$propertyName -key ($keys | Select-Object -Skip 1) -value $value
}
}
用法
$Obj = ConvertFrom-Json '{ "A": "x", "B": {"C": {"D" : "y"}} }'
SetValue $Obj -key "B.C.D".Split(".") -value "z"
GetValue $Obj -key "B.C.D".Split(".")