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

Powershell-.Net数组-无法索引到空数组中,.net,arrays,powershell,.net,Arrays,Powershell,我一直在学习powershell,但我遇到了一个问题,我一直在尝试学习如何使用阵列,并发现有很多方法可以做到这一点。一些阵列的CPU/内存效率低下,而另一些阵列则没有(互联网就是这么说的)。我认为我所做的只是参考.Net阵列,但还不能完全理解它 这是我学习的源泉: 我的两个问题是: 有更好的办法吗?(这样我就不会浪费时间了) 我的语法正确吗 错误: Cannot index into a null array. At C:\Test\custadmin.ps1:54 char:34 + out-

我一直在学习powershell,但我遇到了一个问题,我一直在尝试学习如何使用阵列,并发现有很多方法可以做到这一点。一些阵列的CPU/内存效率低下,而另一些阵列则没有(互联网就是这么说的)。我认为我所做的只是参考.Net阵列,但还不能完全理解它

这是我学习的源泉:

我的两个问题是: 有更好的办法吗?(这样我就不会浪费时间了) 我的语法正确吗

错误:

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

是的,有更好的办法。PowerShell一直在幕后使用.Net阵列,因此您确实不需要显式使用ArrayList等

如果您需要PowerShell中的阵列,可以通过多种方式创建它们。在PowerShell中,它是如此自然以至于几乎对您隐藏。例如:

 $array = 1,2,3

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

包含关于数组和数组使用语义的一般建议

在这一点上,值得重复伯特的建议:为您的特定用例使用数组似乎是错误的;单个变量有助于实现更具可读性和可维护性的解决方案

本答案的其余部分将此方面放在一边(可能代码的细节是次要的,您的问题是关于数组的一般使用),并展示了如何以PowerShell惯用的方式使用数组和其他语法功能。


除非性能至关重要(例如逐渐构建大型阵列时),使用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()
    或其泛型强类型表;e、 例如,对于
    [string]
    实例,
    $list=[System.Collections.Generic.list[string]]::new()

    虽然PowerShell可以方便地使用
    +=
    来“扩展”阵列,但每次都必须在幕后分配一个全新的阵列

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


看起来您使用
$log[0]::$log[1]
的目的只是将
$log[0]
$log[1]
连接起来,在这种情况下,您有几个选项-请注意,
$log[2]
而不是
$log[3]
必须与
-InputObject
一起使用,因为正如伯特指出的那样,
2
是最后一个元素的索引,而不是
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类型的静态成员(属性和方法)的访问-请参阅

$log[0]
属于
[string]
类型,因此
查找该类型的静态成员

因为
的优先级高于
[]
-请参阅-
$log[0]:$log
首先计算,它将查找名称为
$log
值的静态成员

由于成员名称是字符串,
$log
是数组,
$log
被强制为字符串,在PowerShell中是数组元素的空格分隔列表

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


[0]
然后应用于
$null
,这是无效的,并导致您看到的错误(
无法索引到null数组。
)。

使用
$log[0]:$log[1]符号有什么用?您是否希望字符串
“\\Example srv sbs\Logs\”
公开一个名为
2017612Werezwolf.txt
的方法?您试图以您可能不应该的方式对此进行优化-即使这对运行时间有明显影响(不太可能),但这是以可读性为代价的,如果你想从一种脚本语言中挤出几秒钟的时间,你也可以切换到一种编译语言。这两方面都是很好的建议,但请注意错误的原因只是
$log[0]:$log[1]
,而不是缺少任何数组元素。(顺便说一句:
Out File
不会抱怨
$null
被传递到
-InputObject
-它只会写一个空文件(除了BOM))@mklement0,谢谢你说得对,
$log[3]
没有生成错误,但这是一个使用命名变量比数组元素更好的好例子。通过启用
设置StrictMode-最新版本
,您可以看到这些错误。感谢您关注
[3]
问题-甚至没有注意到-答案已更新。我同意在这个用例中数组是一个糟糕的选择——这就是为什么我链接到您的答案(提到“数组使用的语义”),但是我添加了一个更明确的建议。也就是说,我的答案是基于这样的假设,即OP正在与PowerShell的各种语法方面进行斗争,并且特定用例是次要的。@Burt_Harris:我已经重新构造了答案,以便从
# * 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"
# 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]