【问题标题】:powershell hashtable key versus object propertypowershell 哈希表键与对象属性
【发布时间】:2018-02-28 18:44:00
【问题描述】:

我对 PowerShell 如何处理 Hashtable 键和对象属性感到困惑。

考虑:

$list = @{
    'one' = @{
        name  = 'one'
        order = 80
        };

    'two' = @{
        name  = 'two'
        order = 40
        };

    'twotwo' = @{
        name  = 'twotwo'
        order = 40
        };

    'three' = @{
        name  = 'three'
        order = 20
        }
    }

$list.Values|group-object { $_.order }
$list.Values|group-object -property order

第一个 Group-Object 给了我我所期望的(三个组),第二个没有(一个大组)。显然 Hashtable 键不是对象属性,但在语法上它们以相同的方式引用(var.name)。

第二个组对象实际上在做什么?
它认为“订单”属性是什么?

【问题讨论】:

  • 首先值得注意的是,第一个示例中的$_.order 是语法糖,它被翻译为(并执行为)$_['order']

标签: powershell


【解决方案1】:

这是可以理解的混淆,但正如您所说,哈希表键不是对象属性。

对它们一视同仁可能很诱人(有时这样有效),但这种情况绝对不会。

部分原因是您使用的是不同的 cmdlet,而不是直接的语言语义。

哈希表可以对它们的键使用点表示法,但键是不是属性,当您使用Group-Object-Property 参数时,您正在寻找专门的属性,而不仅仅是“任何东西”你可以用一个点访问”。

如您所见,采用脚本块的该参数的另一种形式是将执行的代码,因此块返回的任何值都会被分组。

更直接地回答您的问题:

第二个组对象实际上在做什么?

它正在当前对象(即哈希表)上(特别是)寻找 属性

如果您想查看其中一个对象的属性是什么样的,请尝试以下操作:

$list.Values[0].PSObject.Properties | ft

它认为'order'属性是什么?

它不认为它是什么;它查找具有该名称的属性,如果找到,则使用该值;否则它使用$null

你会得到相同的结果:

$list.Values | group -Property FakeProp

$list.Values | group -Property { $null }

在评论中解决您的问题:

有什么方法可以知道“什么时候应该”和“什么时候不应该”, 我应该只是推迟使用脚本块,什么时候使用-Property 优先于 { ... }?

-Property(不带脚本块)是首选,只要您要分组的值可用作被检查对象的直接属性。如果它是某个属性的属性、某个计算值、哈希表键/值或其他任何内容,请使用脚本块。我将这些称为“复杂值”。

如果复杂值有用,您可能希望将其添加为对象本身的实际属性来封装它;那么你可以直接引用它。此示例并不真正适合您的哈希表情况,但请考虑代表人的对象。它们有 2 个属性:NameDateOfBirth

$people 是这些对象的数组,您想按年龄对人进行分组(请忽略我不准确的年龄确定代码)。

$people | Group-Object -Property { ([DateTime]::Now - $_.DateOfBirth).Days / 365 -as [int] }

如果您再也不需要知道年龄也没关系;当然这不太可能,而且这看起来有点乱。应该更直接地明确您要“按年龄分组”。

相反,您可以使用Add-Member 将自己的(计算的)Age 属性添加到现有对象:

$people |
    Add-Member -MemberType ScriptProperty -Name Age -Value {
        ([DateTime]::Now - $this.DateOfBirth).Days / 365 -as [int]
    } -Force

从现在开始,$people 数组中的每个对象都有一个 Age 属性,该属性是根据 DateOfBirth 属性的值计算得出的。

现在你可以让你的代码更清晰了:

$people | Group-Object -Property Age

同样,这并不能真正解决您的哈希表问题;事实是它们在分组方面效果不佳。如果您要对它们进行大量分组,并且您真的不需要哈希表,请将它们变成对象:

$objs = $list.Values |
    ForEach-Object -Process {
        New-Object -TypeName PSObject -Property $_ # takes a hashtable
    }

$objs = $list.Values |
    ForEach-Object -Process {
        [PSCustomObject]$_ # converts a hashtable to PSObject
    }

然后:

$objs | Group-Object -Property Order

【讨论】:

  • 有什么方法可以知道“什么时候应该”和“什么时候不应该”,我应该推迟使用脚本块,什么时候-Property 的使用优于 { ... }?
  • @Dweeberly 我对你问题的回答很快就失控了,所以我将其添加为编辑;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 2016-04-29
  • 2015-10-26
相关资源
最近更新 更多