powershell 添加别名属性(AliasProperty成员)

hs1rzwqc  于 2023-10-18  发布在  Shell
关注(0)|答案(1)|浏览(128)

我只是想知道为什么它会起作用:

$s = "hi there"
$s = Add-Member -InputObject $s -MemberType AliasProperty -Name Length2 -Value Length -PassThru
$s | gm -MemberType AliasProperty #the property is there
$s.Length2 #8

这意味着:别名属性Length2存在,但这不起作用:

$s = dir
$s = Add-Member -InputObject $s -MemberType AliasProperty -Name Length2 -Value Length -PassThru
$s | gm -MemberType AliasProperty #the property is not there

意味着:没有别名属性Length2,但令人惊讶的是:

$s.Length2 #458

工作正常吗

t98cgbkg

t98cgbkg1#

$s = dir
由于dirGet-ChildItem的内置别名,这 * 通常 * 会导致在$s中存储 * 数组 *,即只要存在 * 两个或更多 * 子项(文件或子目录)。[1]
$s = Add-Member -InputObject $s ...
由于使用了Add-Member-InputObject参数,您将alias属性(作为ETS (Extended Type System)成员)添加到 * 数组本身 *。
$s | gm -MemberType AliasProperty
相比之下,由于在这里使用了 * 枚举 * 数组的 * 管道 *,因此将$s中存储的数组的 * 元素 * 发送到Get-Member(其内置别名为gm)-并且这些元素 * 没有 * 您的alias属性。
$s.Length2 #458
在这里,您直接访问数组上的alias属性,因此可以正常工作。
至于你的 * 第一次 * 尝试(如预期的那样工作):

$s = "hi there"
$s = Add-Member -InputObject $s -MemberType AliasProperty -Name Length2 -Value Length -PassThru
  • 这里$s是一个 scalar(单个对象),即一个[string]示例,您将alias属性直接附加到它。
  • 顺便说一句:请参阅下一节,了解为什么最好避免[string]示例的自定义成员。
  • 通过管道($s | gm -MemberType AliasProperty)发送标量时,标量会按原样发送,因此Get-Membergm)能够找到其.Length2别名属性。

可选阅读:为什么最好避免将ETS (Extended Type System)成员附加到 * [string] * 和 *.NET值类型 * 的 * 示例 *:

注意事项:

  • 以下建议适用于Add-Member能够添加到.NET类型的 * 示例 * 的任何类型的ETS成员,特别是更常见的NoteProperty成员。
  • 请参阅下一节,了解通过 * 类型级别 * ETS成员可能 * 绕过 * 问题。
  • 避免 * 附加ETS * 示例 * 成员**:
  • 到**[string]示例**,因为它们需要一个 * 不可见的[psobject] Package 器 *,该 Package 器 * 容易丢失 *,例如在字符串操作和强类型参数绑定期间,导致ETS成员丢失;例如:
$s = "hi there"

# Add a .Length2 alias property that refers to .Length
$s = Add-Member -InputObject $s -MemberType AliasProperty -Name Length2 -Value Length -PassThru -Force

# OK: access the property directly on the decorated instance.
$s.Length2 # -> 8, same as $s.Length

# LOSS OF THE PROPERTY due to string operation.
$s = $s -replace '$', '!'
$s.Length2 # !! Property was LOST in the -replace operation.

# LOSS OF THE PROPERTY during strongly typed parameter binding
$s = Add-Member -InputObject $s -MemberType AliasProperty -Name Length2 -Value Length -PassThru -Force
& { param([string] $str) $str.Length2 } $s
  • .NET value types示例(例如,[int]System.Int32);在类型上调用.IsValueType来检查),原因类似:它们也可能在强类型参数绑定 * 和 * 过程中丢失,相反-因为PowerShell内部缓存了从0100[int]示例,包括在内-当这些数字被用作 * 文字 * 时,可能会使ETS成员意外出现。
$n = 42

# Add a .Foo instance property of type NoteProperty with value 'Bar'
$n = Add-Member -InputObject $n -MemberType NoteProperty -Name  Foo -Value Bar -PassThru

# OK: access the property directly on the decorated instance.
$n.Foo # -> 'Bar'

# LOSS OF THE PROPERTY during strongly typed parameter binding
& { param([int] $num) $num.Foo } $n

# UNEXPECTED SURFACING OF THE PROPERTY in *integer literals*,
# because the value is between 0 and 100.
[int] $nCopy = 42
$nCopy.Foo # !! -> 'Bar'

注意事项:

  • 这是一个不可见的[psobject] Package 器的必要性,它需要在上面的Add-Member调用中使用-PassThru,沿着 * 将结果重新分配给原始变量 *($s = Add-Member -PassThru -InputObject $s ...
  • 相比之下,对于[string] * 以外的.NET reference types * 的装饰示例,这种调用形式是 * 不 * 必要的,并且这些示例不受上述问题的影响。

可选阅读:* 示例 * 级别与 * 类型 * 级别ETS成员:

ETS成员也可以在 type 级别定义(而不是在 instance 级别,即 * 仅用于特定对象 *),即通过Update-TypeData,这是 * 通常优选的 *,尽管并不总是要求/可能的。

  • AliasProperty成员的情况下,type-level 定义是更好的选择,因为给定类型的 * 所有示例 * 都会自动具有此属性:
# Add an alias property 'Length2' to the [string] (System.String) *type*
Update-TypeData -TypeName System.String -MemberType AliasProperty -MemberName Length2 -Value Length

# Now every string instance has this property.
'foo'.Length2 # -> 3
  • instance-specificNoteProperty成员值的情况下,如果该值可以通过ScriptProperty成员从示例的类型原生属性 * 派生 *,则作为替代的 type-level 定义仅是一个选项,即其值是 * 动态计算 * 的属性,通过script block{ ... }),可以通过自动$this变量作用于手头的示例;例如:
# Add a `.MaxIndex` script property that is the string's
# length - 1, i.e. the index of the last char. in the string.
Update-TypeData -TypeName System.String -MemberType ScriptProperty -MemberName MaxIndex -Value { $this.Length - 1 }

# Now every string instance has this - dynamically calculated - property.
'foo'.MaxIndex # -> 2
'food'.MaxIndex # -> 3

[1]具体来说,它是一个包含System.IO.FileInfo和/或System.IO.DirectoryInfo示例的[object[]]数组。

相关问题