无法从ScriptProperty返回[BindingList[RandomType]]的问题排查与解决求助
问题:PowerShell类动态ScriptProperty返回BindingList实例为$null
我有一个PowerShell类,会基于Import-Clixml加载的数据动态添加成员,简化核心代码后如下:
class TestClass { [hashtable]$_data = @{} [void]DefineData([object]$data) { $this._data['Data'] = $data $this | Add-Member -MemberType ScriptProperty -Name 'ScriptProperty' -Value { #$this._data['Data'].GetType() | Out-Host return $this._data['Data'] } } }
测试时发现,当传入[BindingList<T>]类型的实例时,通过ScriptProperty获取的值为$null,其他类型(哈希表、PSCustomObject、字符串)都能正常返回原值:
$ClassVar = [TestClass]::new() $OriginalValue = [System.ComponentModel.BindingList[string]]::new() #$OriginalValue = @{} #$OriginalValue = [PSCustomObject]@{ Name = 'Value' } #$OriginalValue = "Test String" $OriginalValue.GetType() $ClassVar.DefineData($OriginalValue) $ReturnValue = $ClassVar.ScriptProperty $ReturnValue.GetType() # 此处会报错,因为$ReturnValue为$null
原因分析
这是PowerShell对可枚举类型的特殊处理导致的:
BindingList<T>实现了IEnumerable接口,属于可枚举集合- 当ScriptProperty的脚本块返回可枚举对象时,PowerShell会自动对其进行枚举
- 如果
BindingList<T>是空的(没有添加任何元素),枚举后没有输出,最终就会返回$null - 其他类型(如哈希表、字符串)要么不实现
IEnumerable,要么PowerShell不会对其自动枚举,所以能正常返回
修复方案(适用于所有数据类型)
有两种简单可靠的方法可以避免自动枚举,确保返回原对象:
方法1:使用Write-Output -NoEnumerate
修改ScriptProperty的脚本块,用Write-Output加上-NoEnumerate参数强制返回原对象:
class TestClass { [hashtable]$_data = @{} [void]DefineData([object]$data) { $this._data['Data'] = $data $this | Add-Member -MemberType ScriptProperty -Name 'ScriptProperty' -Value { return Write-Output $this._data['Data'] -NoEnumerate } } }
方法2:用单元素数组包装后返回
通过逗号运算符创建单元素数组,PowerShell会返回数组本身而不会枚举内部元素,最终能正确返回原对象:
class TestClass { [hashtable]$_data = @{} [void]DefineData([object]$data) { $this._data['Data'] = $data $this | Add-Member -MemberType ScriptProperty -Name 'ScriptProperty' -Value { return ,$this._data['Data'] } } }
验证效果
修改后再运行测试代码,$ReturnValue会正确返回BindingList<string>实例,$ReturnValue.GetType()也会输出正确的类型信息,其他数据类型的返回也不受影响。
内容的提问来源于stack exchange,提问作者Darin
相关产品推荐
相关产品推荐

