为什么.NET Framework ArrayList类.Add方法在PowerShell实现中不起作用?
除非我另外纠正,否则我认为我的故事的整体道德可能是:不要假设本机PowerShell方法将与.NET方法相同,并且在PowerShell中尝试.NET方法时要小心.
我正在寻找的原始解决方案是从一个函数返回一个日期列表,作为一个数组,用户定义的日期范围作为参数.然后引用日期数组来移动和读取以日期戳命名的文件.
我遇到的第一个问题是创建一个动态数组.我不知道我在做什么,并且错误地.Add
在@()
数组声明上调用.NET 方法.
使用"1"参数调用"Add"的异常:"Collection具有固定大小."
我认为我需要找到一个动态数组类型,当我真正的问题是我做得不对时.这让我走向了一个不同的方向,直到很久以后,我发现应该使用+=
语法将对象添加到PowerShell数组中.
无论如何,在我回到如何正确使用PowerShell数组之前,我在其他一些切线上了.
然后我找到了.NET ArrayList
类.好的.现在我有一个动态数组对象.我阅读了文档,其中说我应该使用该.Add
方法向集合中添加元素.
然后开始寻求更深入的理解,因为我经历了几天头脑紧张的挫折试图解决问题.
我制作了一个最初工作的实现.它产生了一个日期范围 - 但它也产生了一些奇怪的行为.我观察到奇怪的日期返回,例如:
0001年1月1日星期一12:00:00 AM
事实证明,我发现这是你执行此操作时获得的结果:
Get-Date 0
该ArrayList
被返回时,首先,索引值的数组元素的列表,然后将数组值.这根本没有任何意义.我开始探索我是否正确地调用函数,我是否遇到某种可变范围问题,或者我是否只是疯了.
我现在相当确信我的挫败感是由于缺乏一个可靠的初学者参考,不仅仅展示了如何进行简单数组实现的几个例子,而是用其他解决方案描述了一些注意事项.
让我在这里解释一下,实现数组/集合的三种方法,以及我试图生成的解决方案 - 即日期范围内的日期列表.
出于某种原因,我最初认为在Powershell中向.NET ArrayList添加元素的正确方法是使用.Add方法.它的记载.我仍然不明白为什么这不起作用(严重 - 有人请赐教).通过实验,我发现通过使用+=
将对象添加到ArrayList 的方法,我可以获得准确的结果.
不要这样做.这绝对是错的.它会产生我上面描述的错误:
Function Get-DateRangeList { [cmdletbinding()] Param ( [datetime] $startDate, [datetime] $endDate ) $datesArray = [System.Collections.ArrayList]@() # Second method for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) { if ($d.DayOfWeek -ne 'Sunday') { $datesArray.Add($d) } } Return $datesArray } # Get one week of dates, ending with yesterday's date $startDate = Get-Date $endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range $startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range $datesList = Get-DateRangeList $startDate $endDate # Loop through the dates Foreach ($d in $datesList) { # Do something with each date, e.g., format the date as part of a list # of date-stamped files to retrieve $d }
现在,下面有三个代码示例,DO WORK.在每个示例中,代码都是相同的.我所做的就是对相应的实例化行和方法行进行注释/取消注释.
首先,使用本机PowerShell数组对象:
Function Get-DateRangeList { [cmdletbinding()] Param ( [datetime] $startDate, [datetime] $endDate ) $datesArray = @() # First method #$datesArray = [System.Collections.ArrayList]@() # Second method #$datesArray = New-Object System.Collections.Generic.List[System.Object] # Third method for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) { if ($d.DayOfWeek -ne 'Sunday') { $datesArray += $d # First and second method: += is the method to add elements to: Powershell array; or .NET ArrayList (confusing) #$datesArray.Add($d) # Third method: .Add is the method to add elements to: .NET Generic List } } Return $datesArray } # Get one week of dates, ending with yesterday's date $startDate = Get-Date $endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range $startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range $datesList = Get-DateRangeList $startDate $endDate # Loop through the dates Foreach ($d in $datesList) { # Do something with each date, e.g., format the date as part of a list # of date-stamped files to retrieve "FileName_{0}.txt" -f $d.ToString("yyyyMMdd") }
其次,使用.NET FrameworkArrayList
:
Function Get-DateRangeList { [cmdletbinding()] Param ( [datetime] $startDate, [datetime] $endDate ) #$datesArray = @() # First method $datesArray = [System.Collections.ArrayList]@() # Second method #$datesArray = New-Object System.Collections.Generic.List[System.Object] # Third method for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) { if ($d.DayOfWeek -ne 'Sunday') { $datesArray += $d # First and second method: += is the method to add elements to: Powershell array; or .NET ArrayList (confusing) #$datesArray.Add($d) # Third method: .Add is the method to add elements to: .NET Generic List } } Return $datesArray } # Get one week of dates, ending with yesterday's date $startDate = Get-Date $endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range $startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range $datesList = Get-DateRangeList $startDate $endDate # Loop through the dates Foreach ($d in $datesList) { # Do something with each date, e.g., format the date as part of a list # of date-stamped files to retrieve "FileName_{0}.txt" -f $d.ToString("yyyyMMdd") }
第三,使用.NET Framework通用列表:
Function Get-DateRangeList { [cmdletbinding()] Param ( [datetime] $startDate, [datetime] $endDate ) #$datesArray = @() # First method #$datesArray = [System.Collections.ArrayList]@() # Second method $datesArray = New-Object System.Collections.Generic.List[System.Object] # Third method for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) { if ($d.DayOfWeek -ne 'Sunday') { #$datesArray += $d # First and second method: += is the method to add elements to: Powershell array; or .NET ArrayList (confusing) $datesArray.Add($d) # Third method: .Add is the method to add elements to: .NET Generic List } } Return $datesArray } # Get one week of dates, ending with yesterday's date $startDate = Get-Date $endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range $startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range $datesList = Get-DateRangeList $startDate $endDate # Loop through the dates Foreach ($d in $datesList) { # Do something with each date, e.g., format the date as part of a list # of date-stamped files to retrieve "FileName_{0}.txt" -f $d.ToString("yyyyMMdd") }
所有这三项工作.为什么你喜欢一个而不是另一个?本机PowerShell数组和.NET Framework ArrayList
类都生成非强类型对象的集合,因此您可以执行此操作(在Powershell数组实现中):
$myArray = @(1, 2, 3, "A", "B", "C")
对于非常大的阵列,Powershell阵列效率不高.对于非常大的集合,ArrayList是更好的选择.
对于非常大的同类型对象集合,.NET Framework通用列表似乎是最佳选择.在我的例子中,我想要一个日期列表.每个日期都是相同的数据类型,因此我不需要混合对象类型.因此,我正在部署的解决方案是上面的第三个工作示例.
我很欣赏Dave Wyatt 2013年关于该主题的Powershell.org文章:PowerShell性能:+ =运算符(以及何时避免它).特别是,该+=
方法在循环内的每个传递中创建一个新的数组对象,添加新元素,然后销毁旧数组.对于大型集合,这变得非常低效.
我发布这些解决方案和讨论,希望其他初学者能更容易找到我想要的答案.
是的 - 这是对的 - 我不坚持某些人的想法是严格的PowerShell语法礼仪.我return
在函数中使用了该语句,因此很明显函数产生了什么.我更喜欢可读代码,这些代码可能看起来庞大而不是紧张.这是我的偏好,我坚持认为.
对于更多PowerShell式的日期列表实现,我向读者推荐The Surly Admin发布的整洁实现.
大多数时候我看到阵列添加,这是完全没必要的.每当表达式返回多个对象时,Powershell管道将自动为您创建数组,并且它将非常有效地执行.
考虑:
Clear-Host Function Get-DateRangeList { [cmdletbinding()] Param ( [datetime] $startDate, [datetime] $endDate ) $datesArray = for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) { if ($d.DayOfWeek -ne 'Sunday') { $d } } Return ,$datesArray } # Get one week of dates, ending with yesterday's date $startDate = Get-Date $endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range $startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range $datesList = Get-DateRangeList $startDate $endDate # Loop through the dates Foreach ($d in $datesList) { # Do something with each date, e.g., format the date as part of a list of date-stamped files to retrieve “FileName_{0}.txt" -f $d.ToString("yyyyMMdd") }
所需要的只是创建和输出您的对象,并将结果分配回您的变量,您将拥有一个数组.