我正在将应用程序从 C# 转换为 PowerShell。如何从 PowerShell 调用 LINQ?
[Data.DataTable]$dt = New-Object System.Data.DataTable
[Data.DataColumn]$column = New-Object System.Data.DataColumn "Id", ([int])
$dt.Columns.Add($column)
# add data
[Data.DataRow]$row = $dt.NewRow() #
$row["Id"] = 1
$dt.Rows.Add($row)
$row = $dt.NewRow() #
$row["Id"] = 2
$dt.Rows.Add($row)
# LINQ in C#: int[] results = dt.AsEnumerable().Select(d => d.Field("Id")).ToArray();
[int[]]$results = [Linq.Enumerable]::Select($dt,[Func[int,int]]{ $args[0]})
# Error: Cannot find an overload for "Select" and the argument count: "2"
Write-Host $results
Run Code Online (Sandbox Code Playgroud)
注意:有关从 PowerShell 使用 LINQ 的限制的一般信息,请参阅这篇文章。
问题是这System.Linq.Enumerable.Select()是一个泛型方法,PowerShell 无法为所需的类型参数指定类型,直到 PowerShell 7.2.x 为止。为了让它工作,必须使用反射,这是相当麻烦的(参见底部部分)。
但是,您可以使用方便的 PowerShell 功能来代替:成员访问枚举允许您直接访问集合(可枚举)上感兴趣的属性,并且 PowerShell 将返回每个元素的属性值:
[int[]] $results = $dt.Id # same as: $dt.Rows.Id
$results # print -> array 1, 2
Run Code Online (Sandbox Code Playgroud)
$dt.Id实际上等同于:$dt | ForEach-Object { $_.Id }
为了完整起见(对于这个用例不值得这样做),这里是基于反射的 LINQ 方法:
笔记:
# Using reflection, get the open definition of the relevant overload of the
# static [Linq.Enumerable]::Select() method.
# ("Open" means: its generic type parameters aren't yet bound, i.e. aren't
# yet instantiated with concrete types.)
$selectMethod = [Linq.Enumerable].GetMethods().Where({
$_.Name -eq 'Select' -and $_.GetParameters()[-1].ParameterType.Name -eq 'Func`2'
}, 'First')
# Close the method with the types at hand and invoke it via reflection.
[int[]] $results = $selectMethod.MakeGenericMethod([Data.DataRow], [int]).Invoke(
# No instance to operate on - the method is static.
$null,
# The arguments for the method, as an array.
(
[Data.DataRow[]] $dt.Rows,
[Func[Data.DataRow,int]] { $args[0].Id }
)
)
# Output the result.
$results
Run Code Online (Sandbox Code Playgroud)
注意,上面只展示了如何实例化泛型.Select()方法。
为了获得一个[System.Collections.Generic.IEnumerable`1[System.Data.DataRow]]实例,使用非惰性数组强制转换 ( [System.Data.DataRow[]]) 来代替 using System.Linq.Enumerable.AsEnumerable()- 使用后者也需要使用基于反射的方法。
从上面可以明显看出,从 PowerShell 使用 LINQ 相当麻烦,至少到 v7.3.1 - GitHub Issue #2226建议将来引入更好的 LINQ 集成。
对于使用动态(间接)指定的数据类型而不是数据类型文字(例如 )的 LINQ 解决方案(甚至更麻烦)的概括,请参阅后续问题的答案。[int]
| 归档时间: |
|
| 查看次数: |
1822 次 |
| 最近记录: |