在C#中使用ValueFromPipelineByPropertyName时获取原始管道对象的方法
如何在C# Cmdlet中获取管道传入的原始对象(使用ValueFromPipelineByPropertyName时)
刚好碰到过类似的场景,给你说个简单靠谱的解决办法——当你用ValueFromPipelineByPropertyName=true绑定单个属性时,想要拿到整个原始管道对象,其实不用找什么复杂的API,只要给你的Cmdlet加个专门接收原始对象的参数就行。
具体实现步骤
首先修改你的Cmdlet代码,新增一个InputObject参数,专门用来接收整个管道对象:
[Cmdlet(VerbsLifecycle.Start, "Foo")] public class StartFooCommand : PSCmdlet { // 这个参数负责接收完整的原始管道对象 [Parameter(ValueFromPipeline = true)] public PSObject InputObject { get; set; } [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string Name { get; set; } protected override void ProcessRecord() { // 这里的InputObject就是你要的原始管道对象 if (InputObject != null) { WriteObject(InputObject); } // 这里正常执行你的Foo相关操作,比如用Name参数做事情 // 示例:WriteVerbose($"Starting Foo for {Name}"); } }
为什么这样可行?
PowerShell的管道绑定逻辑很聪明:当它看到有参数设置了ValueFromPipeline=true(也就是我们的InputObject),同时另一个参数设置了ValueFromPipelineByPropertyName=true(Name),它会先把整个管道对象绑定到InputObject,然后再自动从这个对象里提取Name属性的值绑定到Name参数。这样你既能用到Name属性的值,又能拿到完整的原始对象传递给下一个Cmdlet。
另一种备选方法(不推荐,但可以应急)
如果你不想新增参数,也可以通过GetVariableValue方法获取PowerShell内置的$input变量,但这种方式可读性差,也不符合Cmdlet的设计规范,只适合临时调试用:
protected override void ProcessRecord() { var inputEnumerator = (IEnumerator)GetVariableValue("input"); if (inputEnumerator.MoveNext()) { var pipelineObject = inputEnumerator.Current; WriteObject(pipelineObject); } // 执行Foo操作... }
验证效果
现在你运行脚本:
$foo = New-Object PSObject -prop @{ Name = "Frank"; Bar = "Baz" } $foo | Start-Foo | Use-Foo
Start-Foo会把原始的$foo对象完整输出到管道,Use-Foo就能接收到包含Bar属性的完整对象了。
内容的提问来源于stack exchange,提问作者Chad Schouggins
相关产品推荐
相关产品推荐

