【问题标题】:Setting a global PowerShell variable from a function where the global variable name is a variable passed to the function从函数设置全局 PowerShell 变量,其中全局变量名称是传递给函数的变量
【发布时间】:2018-12-30 03:53:48
【问题描述】:

我需要从一个函数中设置一个全局变量,但不太确定如何去做。

# Set variables
$global:var1
$global:var2
$global:var3

function foo ($a, $b, $c)
{
    # Add $a and $b and set the requested global variable to equal to it
    $c = $a + $b
}

调用函数:

foo 1 2 $global:var3

最终结果:

$global:var3 设置为 3

或者如果我这样调用函数:

foo 1 2 $global:var2

最终结果:

$global:var2 设置为 3

我希望这个例子有意义。传递给函数的第三个变量是要设置的变量的名称。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    您可以使用Set-Variable cmdlet。传递$global:var3 发送$var3,这不是您想要的。您想发送姓名

    $global:var1 = $null
    
    function foo ($a, $b, $varName)
    {
       Set-Variable -Name $varName -Value ($a + $b) -Scope Global
    }
    
    foo 1 2 var1
    

    不过,这不是很好的编程习惯。下面会更直接,以后不太可能引入错误:

    $global:var1 = $null
    
    function ComputeNewValue ($a, $b)
    {
       $a + $b
    }
    
    $global:var1 = ComputeNewValue 1 2
    

    【讨论】:

    • 我可以在用户配置文件中使用 Set-Variable cmdlet 吗?所以每当电脑启动时,它都有那个全局变量?
    • 当我尝试使用 powershell_ise 执行 profile.ps1 并正常执行时。当我尝试使用 & $profile 执行配置文件时,出现错误 parameterBingingValidationException
    【解决方案2】:

    就这么简单:

    $A="1"
    function changeA2 () { $global:A="0"}
    changeA2
    $A
    

    【讨论】:

    • @Schiavini -- 我认为它确实有效。如果它让您失望,请记住第一个 $A 如果直接在 cmd 行上输入,则为全局的,并且在全局范围内尝试时应该被覆盖。如果需要,请尝试在之后添加行 $global:A。这是一个通过分号的单行代码,它接受参数并执行相同的操作:$A = -777;function changeA2 ($p1, $p2) { $global:A=$p1+$p2}; changeA2 4 5; $A; "explicit global: " + $global:A; 现在它是可怕的意大利面条代码吗?那是一个单独的讨论。 ;^) 我偏向于 latkin 的第二种解决方案。
    【解决方案3】:

    我在对自己的代码进行故障排除时遇到了这个问题。

    所以这不起作用...

    $myLogText = ""
    function AddLog ($Message)
    {
        $myLogText += ($Message)
    }
    AddLog ("Hello")
    Write-Host $myLogText
    

    这似乎可以工作,但仅限于PowerShell ISE

    $myLogText = ""
    function AddLog ($Message)
    {
        $global:myLogText += ($Message)
    }
    AddLog ("Hello")
    Write-Host $myLogText
    

    这实际上在 ISE 和命令行中都有效:

    $global:myLogText = ""
    function AddLog ($Message)
    {
        $global:myLogText += ($Message)
    }
    AddLog ("Hello")
    Write-Host $global:myLogText
    

    【讨论】:

    • 我什至无法让第三个示例工作 - 仍然无法通过命令行分配(适用于 VS 和 ISE)
    • 我对这种 powershell 怪异现象感到非常恼火!在我看来,在顶层(不在函数中)声明一个变量应该使它成为全局变量,并且对我来说是有意义的!是的,它确实如此,但仅限于 ISE!因此,您编写代码然后它在控制台中突然中断,因为您在声明变量时没有使用 $global: 。主脚本体中声明的变量怎么可能不是全局变量?
    • 更奇怪的是,您不需要使用 $global: 来处理具有属性的自定义对象。无需 $global 即可从任何地方访问它们:
    【解决方案4】:

    您必须将参数作为引用类型传递。

    #First create the variables (note you have to set them to something)
    $global:var1 = $null
    $global:var2 = $null
    $global:var3 = $null
    
    #The type of the reference argument should be of type [REF]
    function foo ($a, $b, [REF]$c)
    {
        # add $a and $b and set the requested global variable to equal to it
        # Note how you modify the value.
        $c.Value = $a + $b
    }
    
    #You can then call it like this:
    foo 1 2 [REF]$global:var3
    

    【讨论】:

    • 我认为在 PoSH 中最接近真实返回值的是使用 局部变量 来传递值,并且永远不要使用 return被任何形式的输出情况“破坏”function CheckRestart([REF]$retval) { # Some logic $retval.Value = $true } [bool]$restart = $false CheckRestart( [REF]$restart) if ( $restart ) { Restart-Computer -Force }
    【解决方案5】:

    latkin's answer 中的第一个建议似乎不错,尽管我会建议下面不那么冗长的方式。

    PS c:\temp> $global:test="one"
    
    PS c:\temp> $test
    one
    
    PS c:\temp> function changet() {$global:test="two"}
    
    PS c:\temp> changet
    
    PS c:\temp> $test
    two
    

    他的第二个建议是关于不好的编程习惯,在像这样的简单计算中是公平的,但是如果你想从你的变量返回一个更复杂的输出怎么办?例如,如果您希望函数返回数组或对象怎么办?对我来说,这就是 PowerShell 函数似乎严重失败的地方。这意味着您别无选择,只能使用全局变量将其从函数传回。例如:

    PS c:\temp> function changet([byte]$a,[byte]$b,[byte]$c) {$global:test=@(($a+$b),$c,($a+$c))}
    
    PS c:\temp> changet 1 2 3
    
    PS c:\temp> $test
    3
    3
    4
    
    PS C:\nb> $test[2]
    4
    

    我知道这可能有点题外话,但我觉得为了回答最初的问题,我们需要确定全局变量是否是不好的编程习惯,以及在更复杂的函数中是否有更好的方法。 (如果有的话我会感兴趣的。)

    【讨论】:

    【解决方案6】:

    @zdan。好答案。我会像这样改进它......

    我认为在 PowerShell 中最接近真实返回值的方法是使用 局部变量 来传递值,并且永远不要使用 return,因为它可能会被“损坏”任何形式的输出情况

    function CheckRestart([REF]$retval)
    {
        # Some logic
        $retval.Value = $true
    }
    [bool]$restart = $false
    CheckRestart( [REF]$restart)
    if ( $restart )
    {
        Restart-Computer -Force
    }
    

    $restart 变量用于调用函数CheckRestart 的任一端,以明确变量的范围。按照惯例,返回值可以是声明的第一个或最后一个参数。我更喜欢最后一个。

    【讨论】:

      【解决方案7】:

      对我来说它有效:

      function changeA2 () { $global:A="0"}
      changeA2
      $A
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多