Powershell - .Net数组 - 无法索引到空数组

时间:2017-06-12 03:25:05

标签: .net arrays powershell

一直在学习一些PowerShell,我有一个问题,我一直在努力学习如何做数组,并发现有很多方法可以做到这一点。有些阵列是CPU /内存无效的,而其他阵列是无法解决的(所以说互联网)。我相信我正在做的是引用.Net阵列,但却无法完全了解它。

这是我的学习来源:https://ss64.com/ps/syntax-arrays.html

我的两个问题是: 有没有更好的办法? (所以我不要浪费我的时间) 我的语法是否正确?

错误:

Cannot index into a null array.
At C:\Test\custadmin.ps1:54 char:34
+ out-file -filePath $log[0]::$log[ <<<< 1] -encoding 'UTF8' -append -width 200 -inputObject $log[3]
+ CategoryInfo          : InvalidOperation: (1:Int32) [], RuntimeException
+ FullyQualifiedErrorId : NullArray

代码:

#Variables
$date = Get-Date
$dateformat = $date.Year+$date.Month+$date.Day
$site = "Example"
$email = New-Object System.Collections.ArrayList
$log = New-Object System.Collections.ArrayList
$schedule = New-Object System.Collections.ArrayList
$error = New-Object System.Collections.ArrayList

#Array Log Variables

$log.Add("\\$site-srv-sbs\Logs\") > $null #path
$log.Add("$dateformat_"+$env:UserName+".txt") > $null #name
$log.Add("This is a report /n/r --------------------- /n/r/n/r Username: "+$env:UserName+" /n/rComputerName: "+$env:computername+" /n/r/n/r") > $null #body

#Log txt file
out-file -filePath $log[0]::$log[1] -encoding 'UTF8' -append -width 200 -inputObject $log[3]

2 个答案:

答案 0 :(得分:1)

是的,有更好的方法。 PowerShell一直在幕后使用.Net阵列,所以你真的不需要明确地使用ArrayLists等。

如果您需要PowerShell中的数组,可以通过多种方式创建它们。在PowerShell中,它如此自然,几乎隐藏在你身上。例如:

 $array = 1,2,3

 $files = get-childitem *.log

两者都真正创建数组。不要试图通过尝试将所有变量都放入$ log来开始试图找到数组的应用程序,这是不自然的。创建具有有意义名称的变量,而不是必须记住$ log [3]还没有存储任何数据。

答案 1 :(得分:1)

Burt_Harris' helpful answer包含有关数组和数组使用语义的一般建议。

此时值得重复Burt的建议:使用数组 你的特定用例似乎是错误的;个别变量使解决方案更具可读性和可维护性。

这个答案的其余部分将这个方面放在一边(可能是你的代码的细节是次要的,你的问题是关于一般的数组使用)并且显示如何在PowerShell-idiomatic中使用数组和其他语法功能方式。

除非性能至关重要 - 例如在逐渐构建大型数组时 - 使用PowerShell自己的数组(.NET类型为[System.Object[]])比处理更简单[System.Collections.ArrayList]

# * Since all elements are known in advance, simply use `,`, the array-constructor
#   operator to create your array.
# * Also note that I've embedded the variable references directly
#   inside "...", with variable names disambiguated with {...}, where necessary.
# * Finally, /n/r instances have been replaced with `r`n (CRLF) - note that ` (backtick)
#   is the escape char. in PowerShell.
$log = "\\$site-srv-sbs\Logs\",
       "${dateformat}_${env:UserName}.txt",
       "This is a report`r`n---------------------`r`n`r`nUsername: $env:UserName`r`nComputerName: $env:computername`r`n`r`n"

如果效率很重要:

  • 为了有效扩展数组迭代,请使用$arrayList = [System.Collections.ArrayList]::new()或其通用的强类型表兄弟;例如,[string]个实例,$list = [System.Collections.Generic.List[string]]::new() 虽然PowerShell可以方便地让您扩展&#34;一个+=的数组,每次必须在幕后分配一个全新的数组。

  • 为了有效地存储数组(但在shell环境中很少重要)和/或类型安全访问,请使用$list = [System.Collections.Generic.List[int]]::new()例如,但请注意,只有类型(例如[int]),而不是引用类型(例如[string])的存储效率才会提高)。
    值类型的另一个有益副作用是元素访问速度稍快

$log[0]::$log[1]的意图似乎只是 连接 $log[0]$log[1] ,在这种情况下您有几个选项 - 请注意,$log[2]而不是$log[3]必须与-InputObject一起使用,因为正如Burt所指出的,2是最后一个元素的索引,而不是{ {1}}:

3

语法错误的原因

# Use "..." # Inside "...", anything beyond a simple variable access - such as indexed # access here - must be enclosed in $(...), the subexpression operator. Out-File -FilePath "$($log[0])$($log[1])" -encoding UTF8 -append -width 200 -inputObject $log[2] # Alternative, using an expression: Out-File -FilePath ($log[0] + $log[1]) -encoding UTF8 -append -width 200 -inputObject $log[2] # Generally preferable: Using the Join-Path cmdlet Out-File -FilePath (Join-Path $log[0] $log[1]) -encoding UTF8 -append -width 200 -inputObject $log[2] 是静态解除引用运算符,其目的是提供对.NET类型的静态成员(属性和方法)的访问 - 请参阅Get-Help about_Operators

::的类型为$log[0],因此[string]会查找该类型的静态成员。

由于::的优先级高于::,因此请先查看Get-Help about_Operator_Precedence - [],然后查找名称为{{1}的静态成员}}

因为成员名称是字符串$log[0]::$log数组,所以$log被强制转换为字符串,在PowerShell中是以空格分隔的数组元素列表。

显然,类型$log上不存在这样的静态成员,因此表达式的一部分计算为$log

然后将

[string]应用于$null,这是无效的,并导致您看到错误([0])。