PowerShell 支持常量吗?

发布于 2024-08-28 06:20:49 字数 50 浏览 9 评论 0 原文

我想在 PowerShell 中声明一些整数常量。

有什么好的办法吗?

I would like to declare some integer constants in PowerShell.

Is there any good way to do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

清风不识月 2024-09-04 06:20:49

使用

Set-Variable test -Option Constant -Value 100

Set-Variable test -Option ReadOnly -Value 100

“常量”和“只读”之间的区别在于,可以通过删除只读变量(然后重新创建),

Remove-Variable test -Force

而不能删除常量变量(即使使用 -Force)。

有关详细信息,请参阅这篇 TechNet 文章

Use

Set-Variable test -Option Constant -Value 100

or

Set-Variable test -Option ReadOnly -Value 100

The difference between "Constant" and "ReadOnly" is that a read-only variable can be removed (and then re-created) via

Remove-Variable test -Force

whereas a constant variable can't be removed (even with -Force).

See this TechNet article for more details.

记忆で 2024-09-04 06:20:49

这是定义这样的常量的解决方案:

const myConst = 42

来自 http://poshcode.org/4063 的解决方案

    function Set-Constant {
  <#
    .SYNOPSIS
        Creates constants.
    .DESCRIPTION
        This function can help you to create constants so easy as it possible.
        It works as keyword 'const' as such as in C#.
    .EXAMPLE
        PS C:\> Set-Constant a = 10
        PS C:\> $a += 13

        There is a integer constant declaration, so the second line return
        error.
    .EXAMPLE
        PS C:\> const str = "this is a constant string"

        You also can use word 'const' for constant declaration. There is a
        string constant named '$str' in this example.
    .LINK
        Set-Variable
        About_Functions_Advanced_Parameters
  #>
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$true, Position=0)]
    [string][ValidateNotNullOrEmpty()]$Name,

    [Parameter(Mandatory=$true, Position=1)]
    [char][ValidateSet("=")]$Link,

    [Parameter(Mandatory=$true, Position=2)]
    [object][ValidateNotNullOrEmpty()]$Mean,

    [Parameter(Mandatory=$false)]
    [string]$Surround = "script"
  )

  Set-Variable -n $name -val $mean -opt Constant -s $surround
}

Set-Alias const Set-Constant

Here is a solution for defining a constant like this:

const myConst = 42

Solution taken from http://poshcode.org/4063

    function Set-Constant {
  <#
    .SYNOPSIS
        Creates constants.
    .DESCRIPTION
        This function can help you to create constants so easy as it possible.
        It works as keyword 'const' as such as in C#.
    .EXAMPLE
        PS C:\> Set-Constant a = 10
        PS C:\> $a += 13

        There is a integer constant declaration, so the second line return
        error.
    .EXAMPLE
        PS C:\> const str = "this is a constant string"

        You also can use word 'const' for constant declaration. There is a
        string constant named '$str' in this example.
    .LINK
        Set-Variable
        About_Functions_Advanced_Parameters
  #>
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$true, Position=0)]
    [string][ValidateNotNullOrEmpty()]$Name,

    [Parameter(Mandatory=$true, Position=1)]
    [char][ValidateSet("=")]$Link,

    [Parameter(Mandatory=$true, Position=2)]
    [object][ValidateNotNullOrEmpty()]$Mean,

    [Parameter(Mandatory=$false)]
    [string]$Surround = "script"
  )

  Set-Variable -n $name -val $mean -opt Constant -s $surround
}

Set-Alias const Set-Constant
分分钟 2024-09-04 06:20:49

要使用特定类型的值(例如 Int64),您可以显式转换 set-variable 中使用的值。

例如:

set-variable -name test -value ([int64]100) -option Constant

检查一下,

$test | gm

您会发现它是一个 Int64(而不是 Int32,对于值 100 来说这是正常的)。

To use a specific type of value, say Int64, you can explicitly cast the value used in set-variable.

For instance:

set-variable -name test -value ([int64]100) -option Constant

To check,

$test | gm

And you'll see that it is an Int64 (rather than Int32, which would be normal for the value 100).

千里故人稀 2024-09-04 06:20:49

我真的很喜欢 rob 的答案 提供的语法糖:

const myConst = 42

不幸的是,当您定义 模块中的>Set-Constant函数。当从模块外部调用时,它将在定义 Set-Constant 的模块作用域中创建一个常量,而不是调用者的作用域。这使得调用者看不到常量。

以下修改后的函数修复了此问题。该解决方案基于问题此答案“powershell 模块有什么方法可以获取其调用者的范围吗? ”

$null = New-Module {
    function Set-Constant {
        <#
        .SYNOPSIS
            Creates constants.
        .DESCRIPTION
            This function can help you to create constants so easy as it possible.
            It works as keyword 'const' as such as in C#.
        .EXAMPLE
            PS C:\> Set-Constant a = 10
            PS C:\> $a += 13

            There is a integer constant declaration, so the second line return
            error.
        .EXAMPLE
            PS C:\> const str = "this is a constant string"

            You also can use word 'const' for constant declaration. There is a
            string constant named '$str' in this example.
        .LINK
            Set-Variable
            About_Functions_Advanced_Parameters
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory, Position=0)] [string] $Name,
            [Parameter(Mandatory, Position=1)] [char] [ValidateSet('=')] $Link,
            [Parameter(Mandatory, Position=2)] [object] $Value
        )

        try {
            $PSCmdlet.SessionState.PSVariable.Set( 
                [Management.Automation.PSVariable]::new( 
                    $Name, $Value, [Management.Automation.ScopedItemOptions]::Constant ) )
        }
        catch {
            # This makes sure the location of the call to Set-Constant is reported 
            # in the error message, instead of the location of the call to PSVariable.Set().
            $PSCmdlet.WriteError( $_ )
        }
    }
}

Set-Alias const Set-Constant

注释:

  • New-Module 行之所以存在,是因为该函数在从不同范围域调用时才起作用(又名会话状态)。您可以将该函数放入实际的模块文件 (.psm1) 中,但是您无法在同一模块中使用它!内存中模块使其可以从 PowerShell 脚本 (.ps1) 以及模块文件中按原样使用。
  • 我已将参数 -Mean 重命名为 -Value,以与 Set-Variable 保持一致。
  • 该函数可以扩展为选择性地设置 PrivateReadOnlyAllScope 标志。只需将所需的值添加到 PSVariable构造函数,在上面的脚本中通过New-Object调用。

编辑 06/2023:

Set-Constant 和任何基于 Set-Variable -Option Constant 的解决方案的缺点是, VSCode 的 PowerShell 扩展不支持导航到变量的定义,例如通过 Ctrl+Click 变量名称(请参阅此 GitHub 问题)。

我当前的解决方法是像普通变量一样定义常量(因此 VSCode 在 AST 中看到它们的定义),然后通过使用 New-Variable -Force -Option Constant 重新定义它们来使它们成为常量代码>.与Set-Variable相反,New-Variable命令可以覆盖现有变量。

导出常量的典型模块现在看起来像这样:

# Define variables
$CONST_FOO = 42
$CONST_BAR = 23

# Make the variables constant, by redefining them as constants.
Get-Variable CONST_* | ForEach-Object { New-Variable -Name $_.Name -Value $_.Value -Option Constant -Force }

# Export the constants from the module
Export-ModuleMember -Variable CONST_*

这是一个完整的演示:

$null = New-Module {
    $CONST_FOO = 42
    $CONST_BAR = 23
    
    Get-Variable CONST_* | ForEach-Object { New-Variable -Name $_.Name -Value $_.Value -Option Constant -Force }
    Export-ModuleMember -Variable CONST_*
}

# All of these should error out
$CONST_FOO = 0
$CONST_BAR = 0
Remove-Variable CONST_FOO -Force

I really like the syntactic sugar that rob's answer provides:

const myConst = 42

Unfortunately his solution doesn't work as expected when you define the Set-Constant function in a module. When called from outside the module, it will create a constant in the module scope, where Set-Constant is defined, instead of the caller's scope. This makes the constant invisible to the caller.

The following modified function fixes this problem. The solution is based on this answer to the question "Is there any way for a powershell module to get at its caller's scope?".

$null = New-Module {
    function Set-Constant {
        <#
        .SYNOPSIS
            Creates constants.
        .DESCRIPTION
            This function can help you to create constants so easy as it possible.
            It works as keyword 'const' as such as in C#.
        .EXAMPLE
            PS C:\> Set-Constant a = 10
            PS C:\> $a += 13

            There is a integer constant declaration, so the second line return
            error.
        .EXAMPLE
            PS C:\> const str = "this is a constant string"

            You also can use word 'const' for constant declaration. There is a
            string constant named '$str' in this example.
        .LINK
            Set-Variable
            About_Functions_Advanced_Parameters
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory, Position=0)] [string] $Name,
            [Parameter(Mandatory, Position=1)] [char] [ValidateSet('=')] $Link,
            [Parameter(Mandatory, Position=2)] [object] $Value
        )

        try {
            $PSCmdlet.SessionState.PSVariable.Set( 
                [Management.Automation.PSVariable]::new( 
                    $Name, $Value, [Management.Automation.ScopedItemOptions]::Constant ) )
        }
        catch {
            # This makes sure the location of the call to Set-Constant is reported 
            # in the error message, instead of the location of the call to PSVariable.Set().
            $PSCmdlet.WriteError( $_ )
        }
    }
}

Set-Alias const Set-Constant

Notes:

  • The New-Module line is there because the function only works, when called from a different scope domain (aka session state). You could put the function into an actual module file (.psm1), but then you couldn't use it from within that same module! The in-memory module makes it usable as-is from both PowerShell scripts (.ps1) as well as module files.
  • I've renamed the parameter -Mean to -Value, for consistency with Set-Variable.
  • The function could be extended to optionally set the Private, ReadOnly and AllScope flags. Simply add the desired values to the 3rd argument of the PSVariable constructor, which is called in the above script through New-Object.

Edit 06/2023:

A disadvantage of both Set-Constant and any solution based on Set-Variable -Option Constant is, that VSCode's PowerShell extension does not support navigation to the definition of the variable, e. g. by Ctrl+Click on the variable name (see this GitHub issue).

My current workaround is to define the constants like normal variables (so VSCode sees their definition in the AST) and then make them constant by redefining them using New-Variable -Force -Option Constant. Contrary to Set-Variable, the New-Variable command can overwrite existing variables.

A typical module that exports constants, now looks like this:

# Define variables
$CONST_FOO = 42
$CONST_BAR = 23

# Make the variables constant, by redefining them as constants.
Get-Variable CONST_* | ForEach-Object { New-Variable -Name $_.Name -Value $_.Value -Option Constant -Force }

# Export the constants from the module
Export-ModuleMember -Variable CONST_*

Here is a full demo to play around with:

$null = New-Module {
    $CONST_FOO = 42
    $CONST_BAR = 23
    
    Get-Variable CONST_* | ForEach-Object { New-Variable -Name $_.Name -Value $_.Value -Option Constant -Force }
    Export-ModuleMember -Variable CONST_*
}

# All of these should error out
$CONST_FOO = 0
$CONST_BAR = 0
Remove-Variable CONST_FOO -Force
白况 2024-09-04 06:20:49

-option ConstantSet-Variable cmdlet 结合使用:

Set-Variable myvar -option Constant -value 100

现在 $myvar 的常量值为 100 并且无法修改。

Use -option Constant with the Set-Variable cmdlet:

Set-Variable myvar -option Constant -value 100

Now $myvar has a constant value of 100 and cannot be modified.

赢得她心 2024-09-04 06:20:49

通过 psvariable。没有性能增益,并且可以通过反射随意更新:

$var = Set-Variable fakeConst -Value constant -Option Constant -PassThru

$var.GetType().
    GetField('_value', 'NonPublic, Instance').
    SetValue($var, 'nope')
$fakeConst

if ($IsCoreCLR) {
    $field = '_options'
}
else {
    $field = 'options'
}

$var.GetType().
    GetField($field, [System.Reflection.BindingFlags] 'NonPublic, Instance').
    SetValue($var, [System.Management.Automation.ScopedItemOptions]::None)
$fakeConst = 'not a constant anymore :('
$fakeConst

它不是一个真正的常量。如果您想要一个真正的 const,可以通过内联 C# 实现:

$addTypeSplat = @{
    MemberDefinition = 'public const string Const = "myConstValue";'
    Name             = 'MyConstClass'
    Namespace        = 'MyNamespace'
}

Add-Type @addTypeSplat
[MyNamespace.MyConstClass]::Const

或者从 PowerShell 中最接近的方法是使用 PowerShell 类中的 static 属性(来自性能立场):

class MyConst {
    static [string] $Const = 'constValue'
}

There is really 0 benefit from creating a constant thru a psvariable. There is no performance gain and it can be updated via reflection at will:

$var = Set-Variable fakeConst -Value constant -Option Constant -PassThru

$var.GetType().
    GetField('_value', 'NonPublic, Instance').
    SetValue($var, 'nope')
$fakeConst

if ($IsCoreCLR) {
    $field = '_options'
}
else {
    $field = 'options'
}

$var.GetType().
    GetField($field, [System.Reflection.BindingFlags] 'NonPublic, Instance').
    SetValue($var, [System.Management.Automation.ScopedItemOptions]::None)
$fakeConst = 'not a constant anymore :('
$fakeConst

It's not a real constant. If you want a real const the way is thru inline C#:

$addTypeSplat = @{
    MemberDefinition = 'public const string Const = "myConstValue";'
    Name             = 'MyConstClass'
    Namespace        = 'MyNamespace'
}

Add-Type @addTypeSplat
[MyNamespace.MyConstClass]::Const

Or the closest you can get to it from PowerShell is with a static property in a PowerShell Class (from a performance standpoint):

class MyConst {
    static [string] $Const = 'constValue'
}
零時差 2024-09-04 06:20:49

PowerShell v5.0 应该允许

[static] [int] $variable = 42

[static] [DateTime] $thisday

等。

PowerShell v5.0 should allow

[static] [int] $variable = 42

[static] [DateTime] $thisday

and the like.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文