【问题标题】:How does one Transform a Collection of Objects into a Collection of new Objects of another Type in Powershell?如何在 Powershell 中将对象集合转换为另一种类型的新对象集合?
【发布时间】:2019-03-19 17:04:55
【问题描述】:

假设我有一个方法可以获取我的枚举类型ProjectName 的枚举集合,并且有一个Server 对象的集合,我想将这些ProjectNames 关联到一个名为Project 的类型中;我将如何在 Powershell Select-Object(或 LINQ 的 Select 的其他等价物)中执行此操作。

我想在 Powershell 中生成的 C# 等价物是这样的:

var servers = new[]
{
    new Server(/*someOtherProjectsCollection goes here*/),
    new Server(/*someOtherProjectsCollection goes here*/),
    new Server(/*someOtherProjectsCollection goes here*/)
};
var projects = GetProjectNames().Select(projectName => new Project(projectName, servers.Where(server => server.Projects.Any(serverProject => serverProject.Name == projectName))));

但我有的是这样的:

$servers = [Server]::new(/*someOtherProjectsCollection goes here*/), [Server]::new(/*someOtherProjectsCollection goes here*/), [Server]::new(/*someOtherProjectsCollection goes here*/)

$projects = (GetProjectNames()) | Select-Object {
    $selectedProjectName = $_

    return [Project]::new($_, ($servers | Where-Object { $_.projects.Where({ $_ -eq $selectedProjectName }).Count -gt 0 }))
}

当我尝试在 Powershell LSE 中读取 $projects(在最后一行之后的断点上)时,它只是将代码作为字符串返回,我什至无法将其转换为 [Project[]]。我认为问题可能在于在 Select-Object 中使用花括号,但我不确定如何在 Select-Object 中创建新的 Project 对象。

【问题讨论】:

  • ForEach-Object替换Select-Object
  • 顺便说一句:GetProjectNames() 应该是 GetProjectNames,因为 PowerShell cmdlet 和函数的调用方式类似于 shell 命令,而不是 方法。也就是说,参数列表周围没有括号,并且以 空格 分隔的参数(,array 构造为 单个参数)。

标签: linq powershell projection


【解决方案1】:

您希望ForEach-Object 而不是Select-Object 为每个项目名称返回一个新的[Project] 实例;此外,您的代码可以简化:

$projects = GetProjectNames | ForEach-Object {
    $projectName = $_
    [Project]::new(
      $projectName, 
      $servers.Where({ $_.projects -eq $projectName })
    )
}
  • Select-Object 用于根据输入对象的选择属性创建新的自定义对象;相比之下,您正在从每个输入对象构造一个新的特定类型实例,这必须在 ForEach-Object 调用中完成,您可以在其中显式控制输出。

  • $_.projects -eq $projectName 作为条件依赖于 PowerShell 使用带有 array 作为 LHS 的 -eq 的能力,在这种情况下执行 过滤,并过滤 子数组;由于.Where() 将脚本块的输出解释为布尔值,因此空子数组被解释为$false,而具有至少一个元素的子数组被解释为$true

  • 还请注意,鉴于 PowerShell 的 隐式输出 行为,您不需要显式的 return:因为新构造的 [Project] 实例没有分配给变量或发送到其他地方,所以它会自动返回。

【讨论】:

  • 太棒了!因此,使用 Powershell 的 ForEach-Object 隐式返回行为,它会返回第一个返回某些内容且不将其分配给任何内容的语句,还是返回最后一个(或语句块中所有的组合/元组?)?
  • @MattArnold:它将返回 all 语句的输出(如果它们完全产生输出并且该输出未被抑制、捕获或重定向)。虽然这很方便,但它也构成了一个陷阱,因为很容易意外产生输出。使用$null = ... 丢弃不需要的输出。
  • @MattArnold:附注:当一个 cmdlet / 函数 / 脚本 / 脚本块产生多个输出时:如果您将它们传送到另一个命令,它们将被逐个发送一个立即(封闭的cmdlet / 函数/ ...不必先完成运行);如果您在变量中捕获输出,它们将被收集在[object[]] (System.Object[]) 数组中;如果只有 一个 输出对象,则按原样捕获(不创建数组)。
  • 如果您在要返回的实际语句上使用return,是否必须在前面返回值的语句上使用$null = ...
  • @MattArnold:是的。 return <val> 只是 <val>; return 的语法糖,即(隐式)输出语句,然后退出手头的代码单元。唯一的例外是使用 class 关键字创建的 PSv5+ 自定义类,其方法与在 C# 中的工作方式相同:没有隐式输出,强制使用 return - 请参阅 stackoverflow.com/a/54877446/45375
猜你喜欢
  • 2021-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多