具有ref值的递归函数

时间:2017-12-01 09:00:26

标签: powershell

我的功能如下:

function GeneratePermutations() {
    Param(
       [System.Collections.ArrayList]$Lists,
       [ref][System.Collections.ArrayList]$result,
       [Int]$depth,
       [String]$current
    )

    if ($depth -eq $Lists.Count)
    {
       $result.Value.Add($current);
    }
    else
    {
        for ($i = 0; $i -lt $Lists[$depth].Count; $i = $i + 1)
        {
            GeneratePermutations $values $result ($depth + 1) ($current + $Lists[$depth][$i])
            # tried as well:
            # GeneratePermutations $values [ref]($result.Value) ($depth + 1) ($current + $Lists[$depth][$i])
        }
    }
}

我尝试使用它如下:

$x = New-Object System.Collections.ArrayList
GeneratePermutations $values [ref]($x) 0 ""

我得到以下异常(德语):

System.Management.Automation.ParameterBindingArgumentTransformationException: Die
Argumenttransformation für den Parameter "result" kann nicht verarbeitet werden. Der Wert "[ref]" vom Typ
"System.String" kann nicht in den Typ "System.Collections.ArrayList" konvertiert werden. --->
System.Management.Automation.ArgumentTransformationMetadataException: Der Wert "[ref]" vom Typ "System.String" kann
nicht in den Typ "System.Collections.ArrayList" konvertiert werden. --->
System.Management.Automation.PSInvalidCastException: Der Wert "[ref]" vom Typ "System.String" kann nicht in den Typ
"System.Collections.ArrayList" konvertiert werden.
   bei System.Management.Automation.LanguagePrimitives.ThrowInvalidCastException(Object valueToConvert, Type
resultType)
   bei System.Management.Automation.LanguagePrimitives.ConvertNoConversion(Object valueToConvert, Type resultType,
Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   bei System.Management.Automation.LanguagePrimitives.ConversionData`1.Invoke(Object valueToConvert, Type resultType,
Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   bei System.Management.Automation.LanguagePrimitives.ConvertTo(Object valueToConvert, Type resultType, Boolean
recursion, IFormatProvider formatProvider, TypeTable backupTypeTable)
   bei System.Management.Automation.ArgumentTypeConverterAttribute.Transform(EngineIntrinsics engineIntrinsics, Object
inputData, Boolean bindingParameters, Boolean bindingScriptCmdlet)
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.Management.Automation.ArgumentTypeConverterAttribute.Transform(EngineIntrinsics engineIntrinsics, Object
inputData, Boolean bindingParameters, Boolean bindingScriptCmdlet)
   bei System.Management.Automation.ParameterBinderBase.BindParameter(CommandParameterInternal parameter,
CompiledCommandParameter parameterMetadata, ParameterBindingFlags flags)
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception
exception)
   bei System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   bei System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   bei System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
In Zeile:1 Zeichen:1
+ .\process.ps1
+ ~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,process.ps1

我认为我有一个递归重用结果数组的问题,有人能告诉我如何解决这个问题吗?似乎powershell想要将结果数组转换为它显然无法做到的字符串,但为什么它会尝试将其转换为字符串?

2 个答案:

答案 0 :(得分:1)

我在递归函数中通过引用传递参数时遇到了同样的问题,并得出结论,在PowerShell中设置[Ref]类型并不会增加很多值,如果你将它与例如它进行比较。 VBScript ByRef参数。

我找到了解决这个问题的方法:

将您的变量放在HashTable(或PSCustomObject)中,@{Var = $Result}哪些属性将通过引用。在你的情况下,我可能只是使用HashTable而不是数组:

function GeneratePermutations() {
    Param(
       [System.Collections.ArrayList]$Lists,
       [HashTable]$result = @{},
       [Int]$depth,
       [String]$current
    )

    if ($depth -eq $Lists.Count)
    {
       $result.$current = $True;
    }
    else
    {
        for ($i = 0; $i -lt $Lists[$depth].Count; $i = $i + 1)
        {
            GeneratePermutations $values $result ($depth + 1) ($current + $Lists[$depth][$i])
        }
    }
}

或者从参数集中删除相关的$Result变量并创建一个变量,该变量的写作范围来自递归函数的根(并且不会覆盖可能已存在的$Result变量:

If (@(Get-PSCallStack)[1].Command -ne $MyInvocation.MyCommand.Name) {
    New-Variable -Name Result -Option AllScope -Value @()
}
if ($depth -eq $Lists.Count)
    {
        $result.Add($current);
        ...

答案 1 :(得分:0)

以下语法有效:

bin/setup

认为游戏中有一些运算符优先级,见下文。

GeneratePermutations $values ([ref]$x) 0 ""

在第一个实例中,我们得到了引用的文本表示,它的[PS]> [ref]$x Value ----- {, , , ...} [PS]> [ref]$x.gettype() Value ----- System.Collections.ArrayList [PS]> ([ref]$x).gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- False False PSReference`1 System.Management.Automation.PSReference 属性是对象。

在第二个中,我们看到我们仍然得到一个引用,但现在ValueValue,它实际上是一个字符串。可能是当在函数之间传递时,正在处理类型时会有一些反射,或者某些东西正在调用System.Collections.ArrayList,并且函数以此字符串引用结束,导致您看到的错误。

在第三个示例中,您可以看到已经返回了正确的类型,并且当像这样传递给您的函数时,错误消失并且一切都按预期运行。