我试图在PowerShell中使用LINQ.看起来这应该是完全可能的,因为PowerShell是建立在.NET Framework之上的,但我无法让它工作.例如,当我尝试以下(人为的)代码时:
$data = 0..10
[System.Linq.Enumerable]::Where($data, { param($x) $x -gt 5 })
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
无法找到"Where"和参数计数的重载:"2".
不要紧,这可以通过以下方式实现Where-Object.这个问题的关键不是找到在PowerShell中执行此操作的惯用方法.如果我可以使用LINQ,那么PowerShell中的一些任务将更轻松.
use*_*407 45
您的代码的问题是PowerShell无法决定应该强制转换ScriptBlockinstance({ ... })的特定委托类型.因此,它是无法选择的的通用第二个参数类型,具体委托实例化Where方法.并且它也没有明确指定通用参数的语法.要解决此问题,您需要自己将ScriptBlock实例强制转换为正确的委托类型:
$data = 0..10
[System.Linq.Enumerable]::Where($data, [Func[object,bool]]{ param($x) $x -gt 5 })
Run Code Online (Sandbox Code Playgroud)
为什么
[Func[object, bool]]工作,但[Func[int, bool]]不是?
因为你$data就是[object[]],不是[int[]]的,因为PowerShell中创建[object[]]默认的阵列; 但是,您可以[int[]]明确地构造实例:
$intdata = [int[]]$data
[System.Linq.Enumerable]::Where($intdata, [Func[int,bool]]{ param($x) $x -gt 5 })
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 27
为了补充PetSerAl的有用答案以及更广泛的答案来匹配问题的通用标题:
注意:在此GitHub问题中,针对未来版本的PowerShell Core正在讨论对LINQ的直接支持 - 其语法与C#中的语法相当.
在PowerShell中使用LINQ:
您需要PowerShell v3或更高版本.
您不能直接在集合实例上调用LINQ扩展方法,而是必须将LINQ方法作为[System.Linq.Enumerable]第一个参数传递输入集合的类型的静态方法调用.
必须这样做会消除LINQ API的流动性,因为方法链不再是一种选择.相反,您必须以相反的顺序嵌套静态调用.
例如,而不是$inputCollection.Where(...).OrderBy(...)你必须写[Linq.Enumerable]::OrderBy([Linq.Enumerable]::Where($inputCollection, ...), ...)
辅助函数和类:
某些方法(例如.Select(),具有接受通用Func<>委托的参数)(例如,Func<T,TResult>可以使用PowerShell代码,通过应用于脚本块的强制转换来创建;例如:
[Func[object, bool]] { $Args[0].ToString() -eq 'foo' }
Func<>委托的第一个泛型类型参数必须与输入集合的元素类型相匹配; 请记住,PowerShell [object[]]默认创建数组.一些方法,例如.Contains()并且.OrderBy具有接受实现特定接口的对象的参数,例如IEqualityComparer<T>和IComparer<T>; 另外,输入类型可能需要实现IEquatable<T>,以便比较按预期工作,例如.Distinct(); 所有这些都需要编写通常在C#中编写的编译类(尽管您可以通过将带有嵌入式C#代码的字符串传递给Add-Typecmdlet 来从PowerShell创建它们); 但是,在PSv5 +中,您也可以使用自定义PowerShell类,但有一些限制.
通用方法:
一些LINQ 方法本身是通用的,因此需要一个类型参数; PowerShell无法直接调用此类方法,必须使用反射; 例如:
# Obtain a [string]-instantiated method of OfType<T>.
$ofTypeString = [Linq.Enumerable].GetMethod("OfType").MakeGenericMethod([string])
# Output only [string] elements in the collection.
# Note how the array must be nested for the method signature to be recognized.
> $ofTypeString.Invoke($null, (, ('abc', 12, 'def')))
abc
def
Run Code Online (Sandbox Code Playgroud)在LINQ方法返回一个迭代器,而不是一个实际的集合.
但是,在许多情况下,您将能够像使用集合一样使用迭代器,例如通过管道发送它时.
.Count也无法 索引到迭代器; 但是,您可以使用成员枚举.如果确实需要将结果作为静态数组来获取通常的集合行为,请将调用包装在中[Linq.Enumerable]::ToArray(...).
::ToList().有关高级示例,请参阅我的这个答案.
有关所有LINQ方法(包括示例)的概述,请参阅这篇精彩的文章.
简而言之:使用PowerShell中的LINQ非常麻烦,只有在满足以下任何条件时才值得付出努力:
| 归档时间: |
|
| 查看次数: |
21845 次 |
| 最近记录: |