Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 为什么本地定义的变量可以从另一个函数中成功访问?_Powershell_Scope_Event Handling - Fatal编程技术网

Powershell 为什么本地定义的变量可以从另一个函数中成功访问?

Powershell 为什么本地定义的变量可以从另一个函数中成功访问?,powershell,scope,event-handling,Powershell,Scope,Event Handling,请参阅下面的代码。将两个文件放在同一目录中,并从PS ISE运行Form1.ps1 如您所见,(本地)变量$localVar是在事件处理程序$button2\u单击中定义的。因此,我假设$localVar不会/不可能存在于$button2\u Click的范围之外,范围由定义事件处理程序的大括号定义 但是,正如您所看到的,我使用$localVar的内容在函数fA中加载$textbox2.Text。单击Test按钮时,两个文本框都显示$localVar 发生什么事了?为什么可以从fA中访问$but

请参阅下面的代码。将两个文件放在同一目录中,并从PS ISE运行
Form1.ps1

如您所见,(本地)变量
$localVar
是在事件处理程序
$button2\u单击
中定义的。因此,我假设
$localVar
不会/不可能存在于
$button2\u Click
的范围之外,范围由定义事件处理程序的大括号定义

但是,正如您所看到的,我使用
$localVar
的内容在函数
fA
中加载
$textbox2.Text
。单击
Test
按钮时,两个文本框都显示
$localVar

发生什么事了?为什么可以从
fA
中访问
$button2\u Click的
$localVar

表单1.ps1

function fA
{
    $textbox2.Text = $localVar
}

$button2_Click = 
{
    $localVar = "set in `$button2_Click"
    $textbox1.Text = $localVar
    fA
}

. (Join-Path $PSScriptRoot 'Form1.designer.ps1')

$textbox1.Text = ""
$Form1.ShowDialog()
[void][System.Reflection.Assembly]::Load('System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][System.Reflection.Assembly]::Load('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
$Form1 = New-Object -TypeName System.Windows.Forms.Form
[System.Windows.Forms.Button]$button2 = $null
[System.Windows.Forms.TextBox]$textBox1 = $null
[System.Windows.Forms.TextBox]$textBox2 = $null
[System.Windows.Forms.Label]$label1 = $null
[System.Windows.Forms.Label]$label2 = $null
[System.Windows.Forms.Button]$button1 = $null
function InitializeComponent
{
$button2 = (New-Object -TypeName System.Windows.Forms.Button)
$textBox1 = (New-Object -TypeName System.Windows.Forms.TextBox)
$textBox2 = (New-Object -TypeName System.Windows.Forms.TextBox)
$label1 = (New-Object -TypeName System.Windows.Forms.Label)
$label2 = (New-Object -TypeName System.Windows.Forms.Label)
$Form1.SuspendLayout()
#
#button2
#
$button2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]148,[System.Int32]12))
$button2.Name = [System.String]'button2'
$button2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]77,[System.Int32]36))
$button2.TabIndex = [System.Int32]0
$button2.Text = [System.String]'Test'
$button2.UseVisualStyleBackColor = $true
$button2.add_Click($button2_Click)
#
#textBox1
#
$textBox1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]67,[System.Int32]69))
$textBox1.Name = [System.String]'textBox1'
$textBox1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox1.TabIndex = [System.Int32]1
#
#textBox2
#
$textBox2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]247,[System.Int32]69))
$textBox2.Name = [System.String]'textBox2'
$textBox2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox2.TabIndex = [System.Int32]2
#
#label1
#
$label1.AutoSize = $true
$label1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]72))
$label1.Name = [System.String]'label1'
$label1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label1.TabIndex = [System.Int32]3
$label1.Text = [System.String]'textbox1'
#
#label2
#
$label2.AutoSize = $true
$label2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]194,[System.Int32]72))
$label2.Name = [System.String]'label2'
$label2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label2.TabIndex = [System.Int32]4
$label2.Text = [System.String]'textbox2'
#
#Form1
#
$Form1.ClientSize = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]374,[System.Int32]110))
$Form1.Controls.Add($label2)
$Form1.Controls.Add($label1)
$Form1.Controls.Add($textBox2)
$Form1.Controls.Add($textBox1)
$Form1.Controls.Add($button2)
$Form1.Name = [System.String]'Form1'
$Form1.ResumeLayout($false)
$Form1.PerformLayout()
Add-Member -InputObject $Form1 -Name base -Value $base -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button2 -Value $button2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox1 -Value $textBox1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox2 -Value $textBox2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label1 -Value $label1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label2 -Value $label2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button1 -Value $button1 -MemberType NoteProperty
}
. InitializeComponent
Form1.designer.ps1

function fA
{
    $textbox2.Text = $localVar
}

$button2_Click = 
{
    $localVar = "set in `$button2_Click"
    $textbox1.Text = $localVar
    fA
}

. (Join-Path $PSScriptRoot 'Form1.designer.ps1')

$textbox1.Text = ""
$Form1.ShowDialog()
[void][System.Reflection.Assembly]::Load('System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][System.Reflection.Assembly]::Load('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
$Form1 = New-Object -TypeName System.Windows.Forms.Form
[System.Windows.Forms.Button]$button2 = $null
[System.Windows.Forms.TextBox]$textBox1 = $null
[System.Windows.Forms.TextBox]$textBox2 = $null
[System.Windows.Forms.Label]$label1 = $null
[System.Windows.Forms.Label]$label2 = $null
[System.Windows.Forms.Button]$button1 = $null
function InitializeComponent
{
$button2 = (New-Object -TypeName System.Windows.Forms.Button)
$textBox1 = (New-Object -TypeName System.Windows.Forms.TextBox)
$textBox2 = (New-Object -TypeName System.Windows.Forms.TextBox)
$label1 = (New-Object -TypeName System.Windows.Forms.Label)
$label2 = (New-Object -TypeName System.Windows.Forms.Label)
$Form1.SuspendLayout()
#
#button2
#
$button2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]148,[System.Int32]12))
$button2.Name = [System.String]'button2'
$button2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]77,[System.Int32]36))
$button2.TabIndex = [System.Int32]0
$button2.Text = [System.String]'Test'
$button2.UseVisualStyleBackColor = $true
$button2.add_Click($button2_Click)
#
#textBox1
#
$textBox1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]67,[System.Int32]69))
$textBox1.Name = [System.String]'textBox1'
$textBox1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox1.TabIndex = [System.Int32]1
#
#textBox2
#
$textBox2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]247,[System.Int32]69))
$textBox2.Name = [System.String]'textBox2'
$textBox2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox2.TabIndex = [System.Int32]2
#
#label1
#
$label1.AutoSize = $true
$label1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]72))
$label1.Name = [System.String]'label1'
$label1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label1.TabIndex = [System.Int32]3
$label1.Text = [System.String]'textbox1'
#
#label2
#
$label2.AutoSize = $true
$label2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]194,[System.Int32]72))
$label2.Name = [System.String]'label2'
$label2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label2.TabIndex = [System.Int32]4
$label2.Text = [System.String]'textbox2'
#
#Form1
#
$Form1.ClientSize = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]374,[System.Int32]110))
$Form1.Controls.Add($label2)
$Form1.Controls.Add($label1)
$Form1.Controls.Add($textBox2)
$Form1.Controls.Add($textBox1)
$Form1.Controls.Add($button2)
$Form1.Name = [System.String]'Form1'
$Form1.ResumeLayout($false)
$Form1.PerformLayout()
Add-Member -InputObject $Form1 -Name base -Value $base -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button2 -Value $button2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox1 -Value $textBox1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox2 -Value $textBox2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label1 -Value $label1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label2 -Value $label2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button1 -Value $button1 -MemberType NoteProperty
}
. InitializeComponent

您好,所以在ISE中有Powershell选项卡和脚本选项卡

Powershell选项卡类似于运行单个Powershell控制台。powershell选项卡中的每个脚本选项卡都在使用该控制台。因此,如果在一个脚本中定义

$Hello = "TEST"
然后在ise中运行。然后在运行的同一powershell选项卡的另一个脚本选项卡中

美元你好

输出将是“测试”

这称为范围。基本上,代码可以看到哪些变量。 在powershell实例中创建的所有变量始终可以在该实例的其余部分中访问

让我们更深入一点,再看一下你们的例子

function fA
{
    $textbox2.Text = $localVar
}

$button2_Click = 
{
    $localVar = "123"
    $textbox1.Text = $localVar
    fA
}
$localVar是第一次单击时创建的。范围将从该范围扩展到其后创建的任何内容。因此调用FA并将$localvar带入FA范围。文本框1和2显示123。但是,让我们来展示一下,这一点仍然存在,而且不是全球性的

function TB1
{
    $localVar = "456"
    $textbox1.Text = $localVar # Will output 456
}

function TB2{
    $textbox2.Text = $localVar # Will output 123
}
$button2_Click = 
{
    $localVar = "123"
    TB1
    TB2
    fA
}
$localVar首次创建。传递给第一个函数的$localvar仍然是123,但在函数中它更改为456。一旦它离开那里,它就转到第二个函数,其中它的$Localvar将等于123
函数中更改的变量不会影响其父函数中的变量,即调用方的按钮2\u单击函数
fA
会看到您的变量,因为它在创建
$localVar
的脚本块的子范围内运行-这是一般的PowerShell行为,而且不是针对ISE的

当您使用
$localVar=…
创建变量时,它在以下意义上是本地的:

  • 在同一作用域中可见并可直接修改,但不在任何父作用域中。

  • 在所有子作用域中都可见,但不可直接修改。

    • 警告:从导入的函数在单独的作用域(也称为会话(子)状态)中运行,该作用域仅作为祖先共享全局作用域,代码在模块外部和其他模块中运行。因此,如果调用者处于非模块代码(全局作用域除外)中或来自其他模块,则从函数导入的模块看不到调用者的变量(以及函数和别名)。
      另一种说法是:从模块导入的函数不在非模块调用方的子作用域中运行(在全局作用域之外),因此看不到该调用方的定义

    • 您可以使用
      $private:
      范围修饰符来防止子范围看到变量

    • 如果分配给最初在父作用域中创建的变量(仅按名称分配),(例如,
      $localVar=…
      ),则将在当前作用域中创建一个新的局部变量,该变量将隐藏原始变量

      • 可以修改父作用域的变量,但您需要使用
        设置变量-scope
        或作用域修饰符,如
        $script:
        (请参阅下面的链接)
有关详细信息,请参阅:

  • 本文的最后一节提供了一个简明的总结


这里有一本关于这方面的好书。可用的作用域选项有:专用、本地、脚本和全局。如果要确保您的
$localVar
仅在其本地范围内可用,则需要将其更改为:
$Private:localVar
。另外,如果在脚本末尾没有销毁变量,它将保存在Shell-Global中Scope@NovaSysEng,我建议您删除
Form1.designer.ps1
代码,因为这是您的问题的附带内容,会分散您的注意力?您问题的核心是,当您的
$button2\u点击
脚本块被调用时,无论以何种方式调用函数
fA
,让
fA
看到调用脚本块的
$localVar
变量(值),这不是您所期望的。不同意-我希望人们能够运行代码来查看问题。Form1.designer.ps1没有那么多代码我的问题不是为什么在一个脚本选项卡中定义的变量可以在另一个脚本选项卡中访问。脚本选项卡之间的透视图不是我所关心的。我的问题是,为什么在一个脚本块(My
$button2\u Click
)中定义的变量可以在另一个脚本块(My function
fA
)中访问?。如果PowerShell不在脚本块之间强制作用域,而不必显式地将每个变量定义为
local
,那么为什么还要担心作用域呢?。假设PowerShell将所有变量视为
$global
?这没有道理。我想我遗漏了一些更基本的东西——漂亮、简洁、概括。我只是很抱歉,我不能把它从为我自己获取有关_示波器的帮助中拔出来。我想我一直认为函数是黑箱,除非它们被明确定义为gl,否则无法看到在别处建立的变量