我正在开发一个 Powershell 模块,该模块需要调用接受字符串列表参数的 .NET 方法。该方法根据字符串集合构造一个 REST URL,以便在单个 API 调用中检索列表中所有元素的结果:
var MyAPIConnector = new APIConnector();
var elements = File.ReadAllLines(@"C:\temp\myfile.txt").ToList();
List<ApiResult> Result = MyAPIConnector.GetResult(elements);
此代码将在几秒钟内执行。
在我的 Powershell 模块中,相同的操作需要更长的时间。以下是该模块的编码方式:
[Cmdlet(VerbsCommon.Get, "ApiResult")]
[OutputType(typeof(ApiResult))]
public class GetApiResults : Cmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public string[] Identity {get; set;}
private List<string> Input;
private List<ApiResult> Result;
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
base.ProcessRecord();
Result = MyAPIConnector.GetResult(Identity.ToList());
WriteObject(Result);
}
}
如果我以与示例程序相同的方式使用 Cmdlet:
$Result = Get-Content -Path 'C:\temp\myfile.txt' | Get-ApiResult
返回相同的结果,但速度慢得多。通过调试,我能够确定,虽然在我的 Cmdlet 源代码中,我使用 Linq 将字符串数组 Identity 转换为列表,但为数组的每个元素单独调用 MyAPIConnector.GetResult() !谁能解释一下这是为什么吗?
最佳答案
更新:更正 - 我错误地写了这篇文章,建议在使用 -OutBuffer 时缓冲传入的对象,这是没有意义的。一次只能处理来自管道的 1 个入站对象。不过,您可以使用 OutBuffer 参数来控制从 cmdlet 沿管道发送的对象数量,如下所述。不过,OutBuffer 不会以任何方式帮助您解决问题:) 正如下面最后一段中所建议的,您可以调用 cmdlet 并直接提供字符串数组作为 -Identity 的参数,这将允许您以以下方式使用 Linq:你想要的。
现在了解一下 OutBuffer :)
有一个名为 -OutBuffer
的通用参数,它将使用一个整数来定义它在输出之前保存的对象的数量。尽管如此,每个对象在收到时都会被单独处理。结果将被缓冲,直到满足给定的 OutBuffer + 1 或没有更多对象为止。
考虑以下示例
我将使用以下测试函数来演示
Function Test-PipelineInput
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
[string[]]$Identity
)
Process {
if ($Identity){
foreach ($item in $Identity) {
$item
}
Write-Host "---End process block"
}
}
}
没有-OutBuffer
$Gettysburg | Select -First 9 | Test-PipelineInput
Four score and seven years ago our
---End process block
fathers brought forth on this continent,
---End process block
a new nation, conceived in Liberty, and
---End process block
dedicated to the proposition that all
---End process block
men are created equal.
---End process block
Now we are engaged in a great
---End process block
civil war, testing whether that
---End process block
nation, or any nation so conceived
---End process block
and so dedicated, can long endure.
---End process block
使用 -Outbuffer 2(缓冲区 2 和第 3 个进程)
$Gettysburg | Select -First 9 | Test-PipelineInput -OutBuffer 2
---End process block
---End process block
Four score and seven years ago our
fathers brought forth on this continent,
a new nation, conceived in Liberty, and
---End process block
---End process block
---End process block
dedicated to the proposition that all
men are created equal.
Now we are engaged in a great
---End process block
---End process block
---End process block
civil war, testing whether that
nation, or any nation so conceived
and so dedicated, can long endure.
---End process block
因此,您可以在这里看到进程 block 如何在前 2 个接收到的对象中不会接收任何对象,然后在第 3 个接收到的对象上进行处理,依此类推。 更新:更正 - 当接收到每个单独的对象时,进程 block 将在每个对象上运行并保存输出对象,直到 buffer + 1 个对象排队。但这仍然不会给你你想要的东西。如果您希望使用 Linq 立即将整个数组发送到函数中进行处理,则可以使用下面的选项(不使用管道)
此外,您也可以将其作为参数传递给 -Identity 参数,而不是通过管道发送对象,您的函数将在其中接收完整的字符串数组并完全处理它
Test-PipelineInput -Identity ( $Gettysburg | Select -First 15 )
Four score and seven years ago our
fathers brought forth on this continent,
a new nation, conceived in Liberty, and
dedicated to the proposition that all
men are created equal.
Now we are engaged in a great
civil war, testing whether that
nation, or any nation so conceived
and so dedicated, can long endure.
We are met on a great battle-field
of that war. We have come to dedicate
a portion of that field, as a final
resting place for those who here gave
their lives that that nation might
live. It is altogether fitting and
---End process block
最后更新: 添加一元数组运算符(数组前面的逗号)将允许数组通过管道传输到下一个命令。我最初认为这不起作用,但事实并非如此。
,($Gettysburg | Select-Object -First 15) | Test-PipelineInput
Four score and seven years ago our
fathers brought forth on this continent,
a new nation, conceived in Liberty, and
dedicated to the proposition that all
men are created equal.
Now we are engaged in a great
civil war, testing whether that
nation, or any nation so conceived
and so dedicated, can long endure.
We are met on a great battle-field
of that war. We have come to dedicate
a portion of that field, as a final
resting place for those who here gave
their lives that that nation might
live. It is altogether fitting and
---End process block
有关更多信息,请参阅这篇文章 Pipe complete array-objects instead of array items one at a time?
关于c# - Powershell Cmdlet - 为什么一次处理一个 string[] 参数元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66111936/