添加到 System.Collections 的数组时,不能对空值表达式调用方法
You cannot call a method on a null-valued expression when adding to array of System.Collections
我有一个函数 (powershell 5.1),它使用正则表达式从使用相同正则表达式的 3 个单独 files/strings 中获取信息。我想在同一个函数中处理所有 3 个,并且 return 它作为 System.Collections 的数组(也许是 Hashtable ...不确定是否需要)。但我收到上述错误。这样做对我来说很有意义,否则我将有不同的函数使用相同的正则表达式做完全相同的事情。所以我试图重新使用功能在 3 个不同的 strings/files.
上执行相同的正则表达式
我查了一下错误,它说有些东西没有分配。 not assigned 我没有看到我的案例中没有分配什么。
Function ProcessOmAlarmXml{
[cmdletbinding()]
Param ()
Process
{
$OMs = [System.Collections]::new() #this will store the 3 hashtables from the regex
$pathViewBase = 'C:\EndToEnd_view\'
$XML_OmMap_Dirs = @('\OmAlarmMap.xml') #will add the other 2 later
$XML_OmMap_Names = @('Config1','Config2','Config3')
$i = 0
#get each one from array
foreach($omFile in $XML_OmMap_Dirs)
{
$pathToXml = Join-Path -Path $pathViewBase -ChildPath $omFile
if(Test-Path $pathToXml)
{
#get file contents to parse as string
$fileContent = Get-MethodContents -codePath $pathToXml -methodNameToReturn "<Configuration>" -followingMethodName "</Configuration>"
#get the Mapping from omMap xml file
$errorMap = @{}
# create array to collect keys that are grouped together
$keys = @()
#regex works perfectly
switch -Regex ($fileContent -split '\r?\n') { #test regex with https://regex101.com/
'Name=\"(\w+-\w+)' { #12-5704
# add relevant key to key collection
$keys = $Matches[1] } #only match once
'^[\s]+<Value Name="MsgTag[">]+(\w+[.\w]*)<\/Value' { # gets the word after MsgTag, before closing tag (\w+)<\/Value MsgTag[">]+(\w+)<\/Value ([?:<!\s\S]?"MsgTag[">]+)(\w+[.\w]*)<\/Value #fails if line commented out..still captures line
# we've reached the relevant error, set it for all relevant keys
foreach($key in $keys){
#Write-Host "om key: $key"
$errorMap[$key] = $Matches[1]
Write-Host "om key: $key ... value: $($errorMap[$key])"
}
}
'break' {
# reset/clear key collection
$keys = @()
}
}#switch
#I'm trying to add each $errorMap with the name in the array $XML_OmMap_Names so I can pull them out and use them later meaningfully
[void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap}) #gives error message
Write-Host $OMs.Count
Write-Host $OMs -ForegroundColor Cyan
$i++
}#test-Path
else
{
Write-Host "No such path $pathToXml"
}
} #foreach
return $errorMap #will return $OMs later instead
} #end Process
}# End of Function
我也在尝试将我的对象存储在数组中,就像这样似乎正在使用:arrays。
请注意,我试图在这里提供最少量的信息,并希望充分展示该函数的作用,这样就可以理解为什么我需要将哈希表存储在数组中 return 无需重新编写复杂的代码,这仍然非常复杂。如果有人有更多关于如何将数组中的哈希表存储到数组中的所有 3 return 的信息,那就太好了。
有关错误的更多信息:
You cannot call a method on a null-valued expression.
At C:\Users21\temp endToEnd folder while network down\EndToEndParser.ps1:329 char:11
+ [void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap}) #[System. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
回答
你想要
using namespace system.collections.generic
$OMs = [list[object]]::new() #this will store the 3 hashtables from the regex
[object[]]$XML_OmMap_Names = @('Config1','Config2','Config3')
$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
$OMs.Add( $somethingElse )
[System.Collections]
不是有效类型。这就是为什么这是空的。
$OMs = [System.Collections]::new()
$null -eq $OMs # returns True
注意,@()
不是数组构造函数
@('\OmAlarmMap.xml')
要将它们声明为列表,而不是意外地变成标量,您需要的是给它一个类型。
$XML_OmMap_Names = @('Config1','Config2','Config3')
# becomes
[object[]]$XML_OmMap_Names = @('Config1','Config2','Config3')
- 左侧的类型 将声明类型,它们是强类型的。
- 右侧的类型 强制值,但不将它们声明为任何类型。
左手边或右手边,表示它在赋值 =
运算符的哪一边。
using namespace system.collections.generic
$OMs = [list[object]]::new() #this will store the 3 hashtables from the regex
$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
$OMs.Add( $somethingElse )
创建数组:应避免什么
你要避免的是
1] [System.Collections.ArrayList]
和 [System.Collections.Generic[Type]]::new()
这在why generics are better? : microsoft docs
中有解释
2] 像 $s = @()
、$s += stuff
这样的加法,因为每次加法都会分配新的内存。随着大小的增加,它会呈指数级恶化。
你应该做什么
1] 文档说 对于具有混合类型的对象,使用 [list[object]]
using namespace System.Collections.Generic
$items = [list[object]]::new()
$items.Add( '1' )
$items.Add( (Get-Item . ))
2] 对于一种特定类型的对象使用 [list[type]]
$nums = [list[Int64]]::new()
$nums.add( '1' )
$nums[0] -is [Int64] # True
$nums[0] -is [string] # False
3] 如果你不是 +=
ing
,隐式数组是可以的
# now the type is an array, regardless if nothing, or single value return
[object[]]$ArrayOfAnything = FunctionMightReturnNothing # 0-tomany items
[object[]]$AlwaysArray = Get-ChildItem . | Select -first 1
$AlwaysArray.GetType() # type is object[] arrray
$sometimesArray = Get-ChildItem . | select -first 1
$sometimesArray.GetType() # type is a scalar of type [filesysteminfo]
隐式数组很好。
# often in powershell it's more natural to emit output to the pipeline, instead of manually adding arrays.
$results = @(
Get-ChildItem c:\ -depth 3 | Sort-Object LastWriteTime | Select-Object -top 3
if($IncludeProfile) {
Get-ChildItem -file "$Env:UserProfile" -depth 3 | Sort-Object Length | Select-Object -top 3
}
)
链接
听起来你要找的是一个(可能有序的)嵌套 hashtable:
# Initialize an ordered hashtable.
$OMs = [ordered] @{ } # This will later store 3 nested hashtables.
# The (top-level) keys
$XML_OmMap_Names = @('Config1','Config2','Config3')
$i = 0
foreach($someFile in 'foo', 'bar', 'baz') {
# Construct the nested hashtable
$errorMap = [ordered] @{ nested = $someFile }
# Add it to the top-level hashtable.
$OMS.Add($XML_OmMap_Names[$i], $errorMap)
++$i
}
请注意键 $XML_OmMap_Names[$i]
和值 $errorMap
如何作为 单独的参数 传递给 .Add()
方法。
(相比之下,在您的尝试 [void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
中,您错误地将 单个 参数作为 script block ({ ... }
) 传递。)
或者,索引语法 - $OMS[$XML_OmMap_Names[$i]] = $errorMap
- 可用于添加条目;请注意,此方法会悄悄地用相同的键替换任何预先存在的值,而 .Add()
方法会抛出异常。
现在您可以通过名称获取条目;例如:
$OMs.Config1 # Same as: $OMs['Config1']
注意:由于使用了[ordered]
,所以也可以使用positional indices:
$OMs[0] # Same as : $OMs.Config1
也可以直接访问嵌套哈希表的条目:
$OMs.Config1.nested # Same as: $OMs['Config1']['nested'] -> 'foo'
我有一个函数 (powershell 5.1),它使用正则表达式从使用相同正则表达式的 3 个单独 files/strings 中获取信息。我想在同一个函数中处理所有 3 个,并且 return 它作为 System.Collections 的数组(也许是 Hashtable ...不确定是否需要)。但我收到上述错误。这样做对我来说很有意义,否则我将有不同的函数使用相同的正则表达式做完全相同的事情。所以我试图重新使用功能在 3 个不同的 strings/files.
上执行相同的正则表达式我查了一下错误,它说有些东西没有分配。 not assigned 我没有看到我的案例中没有分配什么。
Function ProcessOmAlarmXml{
[cmdletbinding()]
Param ()
Process
{
$OMs = [System.Collections]::new() #this will store the 3 hashtables from the regex
$pathViewBase = 'C:\EndToEnd_view\'
$XML_OmMap_Dirs = @('\OmAlarmMap.xml') #will add the other 2 later
$XML_OmMap_Names = @('Config1','Config2','Config3')
$i = 0
#get each one from array
foreach($omFile in $XML_OmMap_Dirs)
{
$pathToXml = Join-Path -Path $pathViewBase -ChildPath $omFile
if(Test-Path $pathToXml)
{
#get file contents to parse as string
$fileContent = Get-MethodContents -codePath $pathToXml -methodNameToReturn "<Configuration>" -followingMethodName "</Configuration>"
#get the Mapping from omMap xml file
$errorMap = @{}
# create array to collect keys that are grouped together
$keys = @()
#regex works perfectly
switch -Regex ($fileContent -split '\r?\n') { #test regex with https://regex101.com/
'Name=\"(\w+-\w+)' { #12-5704
# add relevant key to key collection
$keys = $Matches[1] } #only match once
'^[\s]+<Value Name="MsgTag[">]+(\w+[.\w]*)<\/Value' { # gets the word after MsgTag, before closing tag (\w+)<\/Value MsgTag[">]+(\w+)<\/Value ([?:<!\s\S]?"MsgTag[">]+)(\w+[.\w]*)<\/Value #fails if line commented out..still captures line
# we've reached the relevant error, set it for all relevant keys
foreach($key in $keys){
#Write-Host "om key: $key"
$errorMap[$key] = $Matches[1]
Write-Host "om key: $key ... value: $($errorMap[$key])"
}
}
'break' {
# reset/clear key collection
$keys = @()
}
}#switch
#I'm trying to add each $errorMap with the name in the array $XML_OmMap_Names so I can pull them out and use them later meaningfully
[void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap}) #gives error message
Write-Host $OMs.Count
Write-Host $OMs -ForegroundColor Cyan
$i++
}#test-Path
else
{
Write-Host "No such path $pathToXml"
}
} #foreach
return $errorMap #will return $OMs later instead
} #end Process
}# End of Function
我也在尝试将我的对象存储在数组中,就像这样似乎正在使用:arrays。
请注意,我试图在这里提供最少量的信息,并希望充分展示该函数的作用,这样就可以理解为什么我需要将哈希表存储在数组中 return 无需重新编写复杂的代码,这仍然非常复杂。如果有人有更多关于如何将数组中的哈希表存储到数组中的所有 3 return 的信息,那就太好了。
有关错误的更多信息:
You cannot call a method on a null-valued expression.
At C:\Users21\temp endToEnd folder while network down\EndToEndParser.ps1:329 char:11
+ [void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap}) #[System. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
回答
你想要
using namespace system.collections.generic
$OMs = [list[object]]::new() #this will store the 3 hashtables from the regex
[object[]]$XML_OmMap_Names = @('Config1','Config2','Config3')
$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
$OMs.Add( $somethingElse )
[System.Collections]
不是有效类型。这就是为什么这是空的。
$OMs = [System.Collections]::new()
$null -eq $OMs # returns True
注意,@()
不是数组构造函数
@('\OmAlarmMap.xml')
要将它们声明为列表,而不是意外地变成标量,您需要的是给它一个类型。
$XML_OmMap_Names = @('Config1','Config2','Config3')
# becomes
[object[]]$XML_OmMap_Names = @('Config1','Config2','Config3')
- 左侧的类型 将声明类型,它们是强类型的。
- 右侧的类型 强制值,但不将它们声明为任何类型。
左手边或右手边,表示它在赋值 =
运算符的哪一边。
using namespace system.collections.generic
$OMs = [list[object]]::new() #this will store the 3 hashtables from the regex
$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
$OMs.Add( $somethingElse )
创建数组:应避免什么
你要避免的是
1] [System.Collections.ArrayList]
和 [System.Collections.Generic[Type]]::new()
这在why generics are better? : microsoft docs
中有解释2] 像 $s = @()
、$s += stuff
这样的加法,因为每次加法都会分配新的内存。随着大小的增加,它会呈指数级恶化。
你应该做什么
1] 文档说 对于具有混合类型的对象,使用 [list[object]]
using namespace System.Collections.Generic
$items = [list[object]]::new()
$items.Add( '1' )
$items.Add( (Get-Item . ))
2] 对于一种特定类型的对象使用 [list[type]]
$nums = [list[Int64]]::new()
$nums.add( '1' )
$nums[0] -is [Int64] # True
$nums[0] -is [string] # False
3] 如果你不是 +=
ing
# now the type is an array, regardless if nothing, or single value return
[object[]]$ArrayOfAnything = FunctionMightReturnNothing # 0-tomany items
[object[]]$AlwaysArray = Get-ChildItem . | Select -first 1
$AlwaysArray.GetType() # type is object[] arrray
$sometimesArray = Get-ChildItem . | select -first 1
$sometimesArray.GetType() # type is a scalar of type [filesysteminfo]
隐式数组很好。
# often in powershell it's more natural to emit output to the pipeline, instead of manually adding arrays.
$results = @(
Get-ChildItem c:\ -depth 3 | Sort-Object LastWriteTime | Select-Object -top 3
if($IncludeProfile) {
Get-ChildItem -file "$Env:UserProfile" -depth 3 | Sort-Object Length | Select-Object -top 3
}
)
链接
听起来你要找的是一个(可能有序的)嵌套 hashtable:
# Initialize an ordered hashtable.
$OMs = [ordered] @{ } # This will later store 3 nested hashtables.
# The (top-level) keys
$XML_OmMap_Names = @('Config1','Config2','Config3')
$i = 0
foreach($someFile in 'foo', 'bar', 'baz') {
# Construct the nested hashtable
$errorMap = [ordered] @{ nested = $someFile }
# Add it to the top-level hashtable.
$OMS.Add($XML_OmMap_Names[$i], $errorMap)
++$i
}
请注意键 $XML_OmMap_Names[$i]
和值 $errorMap
如何作为 单独的参数 传递给 .Add()
方法。
(相比之下,在您的尝试 [void]$OMs.Add({$XML_OmMap_Names[$i]=$errorMap})
中,您错误地将 单个 参数作为 script block ({ ... }
) 传递。)
或者,索引语法 - $OMS[$XML_OmMap_Names[$i]] = $errorMap
- 可用于添加条目;请注意,此方法会悄悄地用相同的键替换任何预先存在的值,而 .Add()
方法会抛出异常。
现在您可以通过名称获取条目;例如:
$OMs.Config1 # Same as: $OMs['Config1']
注意:由于使用了[ordered]
,所以也可以使用positional indices:
$OMs[0] # Same as : $OMs.Config1
也可以直接访问嵌套哈希表的条目:
$OMs.Config1.nested # Same as: $OMs['Config1']['nested'] -> 'foo'