添加隐藏的属性,除非它有值

Adding a property that is hidden unless it has a value

提问人:Vopel 提问时间:7/29/2023 最后编辑:Vopel 更新时间:7/29/2023 访问量:73

问:

我正在添加一个与软件包相关的类。以下是用于此问题的准系统版本:

class Package {
    $Name; $Latest; $Prerelease
    [string]ToString(){ return $this.Name }
}
$test = [Package]::new()
$test.Name = 'Example'
$test.Latest = '0.1'

当我执行命令 or 时,我希望隐藏 $Prerelease 属性,除非它被赋予一个值。$test$test | Format-Table

而且,虽然下一部分不是必需的,但我也希望在使用类似的东西时公开它。Format-Table -Force

我发誓我目睹了 PowerShell 中的其他对象的类似行为,但我无法回忆起它们是什么。如果这对于使用纯 PowerShell 制作的对象不可行,我不介意通过 .Add-Type


附言关于建议替代方案,请记住,我想引用对象来输出 $Name 属性,就像它在我上面发布的类中所做的那样,例如"$test"

PowerShell 对象 属性

评论

0赞 Mathias R. Jessen 7/29/2023
是否要求使用特定类型/自定义类?使用 PSCustomObject 将使这个问题更容易解决(除非你有值,否则不要添加该属性)Prerelease
0赞 Vopel 7/29/2023
@MathiasR.Jessen 我已经考虑过了,但我希望该类具有输出$Name的 ToString() 方法,以便在输入时只需获得 $Name 属性。使用 PSCustomObject 可行吗?此外,我希望它通过管道传递到另一个命令,该命令需要该类作为其 InputObject 参数。我可以将 $Name 属性重命名为花哨的名称,并改用 ValueFromPipelineByPropertyName,但这并不理想。"$test"
0赞 Vopel 7/29/2023
此外,我继续在我的问题中添加了 ToString() 位,以便在有好的替代方案时更好地满足我的需求。

答:

2赞 Mathias R. Jessen 7/29/2023 #1

正如注释中提到的,在有条件地将属性添加到目标哈希表/字典后,只需使用表达式即可更容易实现。[PSCustomObject]

然后,可以将方法的重写添加到生成的对象中:ToString()

function New-VopelPackage {
  param(
    [Parameter(Mandatory = $true)]
    [string]$Name,

    [Parameter(Mandatory = $true)]
    [string]$Latest,

    [Parameter(Mandatory = $false)]
    [switch]$Prerelease
  )

  # Collect the mandatory properties
  $newPackageProperties = [ordered]@{
    Name = $Name
    Latest = $Latest
  }

  # Conditionally add the optional one
  if ($PSBoundParameters.ContainsKey('Prerelease')) {
    $newPackageProperties['Prerelease'] = $Prerelease.IsPresent
  }

  # Create the object
  $package = [PSCustomObject]$newPackageProperties 

  # ... and override ToString()
  $toStringMemberParams = @{
    Name       = 'ToString'
    MemberType = 'ScriptMethod'
    Value      = { return $this.Name }
    Force      = $true
    PassThru   = $true
  }

  return $package |Add-Member @toStringMemberParams
}

现在,您可以使用以下行为创建包对象:

PS ~> $package = New-VopelPackage Example 0.1
PS ~> $package

Name    Latest
----    ------
Example 0.1

PS ~> "$package"
Example
PS ~> $prereleasePackage = New-VopelPackage Example 0.1 -Prerelease
PS ~> $prereleasePackage

Name    Latest Prerelease
----    ------ ----------
Example 0.1          True

PS ~> "$prereleasePackage"
Example

评论

0赞 Vopel 7/29/2023
谢谢。它唯一缺少的是另一个命令以某种方式识别它正在处理的对象无疑是“VopelPackage”。有没有办法向它添加一个可以检查的隐藏属性,或者类似的东西?
0赞 Vopel 7/29/2023
我刚刚发现了 PSTypeName,它应该可以满足我的需求。感谢您的帮助。
0赞 Vopel 8/9/2023
所以,我一直在使用这个解决方案,但我并不完全满意。PSTypeName 在执行管道传输到 Select-Object 等操作时往往会掉落,这会搞砸验证。我认为实际上有一种方法可以做我想做的事,但它需要 C# 代码和比我更多的专业知识。我认为关键是扩展“INotifyPropertyChanged”类,这是我第一次在这里读到的。我添加了 OnPropertyChanged 以确保它在 PowerShell 中触发,并且确实如此。Console.WriteLine("test");
0赞 Vopel 8/9/2023
(续)因此,我使用它的想法是将类属性与 System.Automation 一起使用,然后,每当第一次修改其中一个属性时,使用 AddMember 添加一个新的 ScriptProperty,该属性用作它的 getter,名称将是属性名称加上末尾的空格(因为 PowerShell 允许这样做)。如果您能提供您的专业知识,我将不胜感激。[HiddenAttribute]
0赞 Mathias R. Jessen 8/9/2023
我不确定我这里有足够的上下文,也许你想问另一个问题?请具体说明您要实现的目标