问题
I have a very weird problem happening. I have an object populated with a bunch of rows. I can access them all well, but I need to append a "." (dot) to every value inside it, so I end up converting each record to a string using a for each loop and adding a "." after trimming the values. The issue now however, is that I would like to assign each of these rows (And the rows have only one column/Item) to another array/object, so I can access them later.
The issue is that even when I declare an object/array variable and assign the string converted data rows, the object variable keeps getting converted to a String, and I just cant seem to avoid it.
Please help. Here is a modified code sample:
[String] $DBNms = @();
ForEach($DBName in $objDBNms){
$tempText += $DBName.Item(0).ToString().Trim() + "."
$DBNms += $tempText
}
Write-Host($DBNms.GetType()) #And this is showing up a string, while I want it to be an array.
And if I print $DBNms, it indeed shows up a string concatenated together into a single string, while I actually want it to be like $DBNms[0] = first Item value, $DBNms[1] = second Item value and so on.
回答1:
[String] $DBNms = @();
makes $DBNms
a type-constrained variable, due to type literal [string]
being placed to the left of variable $DBNms
, whose type is then locked in as a string; that is, as a single string.
You were looking to create a string array, which in PowerShell is represented as [string[]]
:
[string[]] $DBNames = @()
PowerShell's type conversions are automatic (and very flexible), so that [String] $DBNms = @()
doesn't report an error, it quietly converts the empty array (@()
) to the empty string (as required by the type constraint):
PS> [string] $DBNames = @(); '' -eq $DBNames
True
A much more efficient way to collect values from multiple iterations in an array is to use the foreach
statement as an expression, which case PowerShell collects the outputs automatically for you:
[string[]] $DBNms = foreach ($DBName in $objDBNms){
# Output this expression's value as-is.
# PowerShell will collect the individual iterations' values for you.
$DBName.Item(0).ToString().Trim() + "."
}
The above is not only more concise than your original approach, it is more importantly more efficient:
In reality you cannot directly add (append to) an array, because it is an immutable data structure.
What PowerShell has to do whenever you use
+=
with an array is to allocate a new array behind the scenes, with the original elements copied over and the new element(s) appended; the new array is then automatically assigned back to the variable.
Note: The alternative and next best solution to using the whole loop as an expression is to use an efficiently extensible list type, notably [System.Collections.Generic.List[object]]
(System.Collections.Generic.List`1):
# Create the list.
# The 'System.' namespace prefix is optional.
[Collections.Generic.List[string]] $DBNms = @()
foreach ($DBName in $objDBNms) {
# Add to the list, using its .Add() method.
# Note: Do NOT try to add with +=
$DBNms.Add($DBName.Item(0).ToString().Trim() + ".")
}
You'll need this approach if your loop does more than outputting a single value per iteration, such as needing to append to multiple collections.
Note: It used to be common to use System.Collections.ArrayList instances instead; however:
Use of this type is no longer recommended (see the warning in the linked help topic); use
[System.Collections.Generic.List[object]]
instead, which additionally allows you to strongly type the collection (replace[object]
with the type of interest, such as[string]
in the code above).It has the drawback of its
.Add()
method having a return value, which you need to silence explicitly (e.g.,$null = $lst.Add(...)
), so that it doesn't accidentally pollute your code's output stream (produce unexpected extra output).
来源:https://stackoverflow.com/questions/60029045/data-rows-to-string-to-array-issue