c# - Powershell Cmdlet - 为什么一次处理一个 string[] 参数元素?

标签 c# powershell

我正在开发一个 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/

相关文章:

c# - 在 core 3.0 中将 View 渲染为字符串 : Could not find an IRouter associated with the ActionContext

c# - 在 C# 中创建复合泛型子类型的泛型列表

Powershell循环和替换(从文本文件读取)

function - 如何在 powershell 函数中传递参数?

shell - 如何防止在 PowerShell 中保存以空格开头的输入历史记录?

powershell - powershell 脚本中的 -contains 和 .contains 有什么区别?

c# - 将数据从非托管代码 (C) 传递到托管代码 (C#)

c# - 如何从Excel中获取工作表名称

c# - 只读的目的

powershell - 如何从已安装的更新窗口获取所有详细信息