【发布时间】:2021-02-11 20:12:24
【问题描述】:
PS版本:5.1
想要的
我希望的会奏效$obj = [PSCustomObject]@{
PSTypeName = 'MyObject'
con = 'local'
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
param([parameter(ValueFromPipeline=$true)]$x)
begin {write-host 'begin'}
process{write-host "$($this.con): $x"}
end {write-host 'end'}
}
1..5 | $obj.MyMethod
给予
begin
local: 1
local: 2
local: 3
local: 4
local: 5
end
但报错
At line:1 char:8
+ 1..5 | $obj.MyMethod
+ ~~~~~~~~~~~~~
Expressions are only allowed as the first element of a pipeline.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpressionsMustBeFirstInPipeline
试过
什么不起作用,因为:idk,tl;dr 原因?1..5 | %{$obj.MyMethod($_)}
什么不起作用,因为:开始/结束
$obj = [PSCustomObject]@{
PSTypeName = 'MyObject'
con = 'local'
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
param($x)
write-host "$($this.con): $x"
}
1..5 | %{$obj.MyMethod($_)}
什么不起作用,因为:$this 不再附加
$obj = [PSCustomObject]@{
PSTypeName = 'MyObject'
con = 'local'
MyMethodSB = {
param()
begin {write-host 'begin'}
process{write-host "$($obj.con): $_"}
end {write-host 'end'}
}
}
1..5 | &$obj.MyMethodSB
什么不起作用,因为:idk,也许 Stepper 的范围过早死亡
$obj = [PSCustomObject]@{
PSTypeName = 'MyObject'
con = 'local'
Stepper = $null
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
param($x)
if($null -eq $this.Stepper){
$t = $this
$sb = {
param($o)
begin {write-host 'begin'}
process{write-host "$($o.con): $_"}
end {write-host 'end'}
}
$this.Stepper = {&$sb $t}.GetSteppablePipeline()
$this.Stepper.Begin($true)
}
$this.Stepper.Process($x)
}
1..5 | %{$obj.MyMethod($_)}
$obj.Stepper.End()
$obj.Stepper = $null
差不多了
什么有点工作$Data = @{
ItemNo1 = @(
@{loc = 'WH'; qty = 20}
@{loc = 'DK'; qty = 0}
@{loc = 'ST1'; qty = 3}
@{loc = 'ST2'; qty = 2}
)
ItemNo2 = @(
@{loc = 'WH'; qty = 6}
@{loc = 'DK'; qty = 0}
)
ItemNo3 = @(
@{loc = 'WH'; qty = 100}
@{loc = 'ST1'; qty = 5}
@{loc = 'DK'; qty = 0}
)
ItemNo4 = @(
@{loc = 'WH'; qty = 0}
@{loc = 'DK'; qty = 0}
@{loc = 'ST2'; qty = 15}
)
ItemNo5 = @(
@{loc = 'WH'; qty = 0}
@{loc = 'DK'; qty = 15}
)
}
$QueryParameter = [PSCustomObject]@{Value = $null}
function MockDataQuery{
$Item = $QueryParameter.Value
foreach($iDat in $Data.$Item){
" $Item;$($iDat.loc);$($iDat.qty)"
}
}
$InvObj = [PSCustomObject]@{
PSTypeName = 'Data.Connection'
con = 'item.inventory'
}
add-member -MemberType ScriptMethod -InputObject $InvObj -Name FetchItemData -Value {
$p = $this
$qPipe = [PSCustomObject]@{
PSTypeName = 'Data.Connection.QueryPipe'
parent = $p
qHeader = 'Item;Location;Quantity'
query = 'select * from inventory where item = ?'
param = $null
}
add-member -MemberType ScriptMethod -InputObject $qPipe -Name begin -Value {
param([bool]$Header=$true)
write-host "connect to: $($this.parent.con)"
write-host "compile command: $($this.query)"
$this.param = $QueryParameter
write-host 'begin transaction'
if($Header){
write-host " $($this.qHeader)"
}
}
add-member -MemberType ScriptMethod -InputObject $qPipe -Name process -Value {
param($itm)
$this.param.Value = $itm
MockDataQuery | write-host
}
add-member -MemberType ScriptMethod -InputObject $qPipe -Name end -Value {
write-host 'end transaction'
write-host 'dispose command'
write-host 'close connection'
}
return $qPipe
}
1..5 | %{"ItemNo$_"} | &{
begin {$stp = $InvObj.FetchItemData();$stp.begin()}
process{$stp.process($_)}
end {$stp.end()}
}
虽然这似乎是一个功能模型,但如果有一种解决方案不需要连接对象的用户每次使用时都必须在其端编写开始/处理/结束脚本,那就更好了对象的方法。
【问题讨论】:
-
您到底想完成什么,为什么使用 ScriptMethod 很重要? ScriptMethods 并非完全设计为像 cmdlet 那样使用。
-
最后一个最接近我的最终用例,一个连接对象,它具有通过参数查询数据的方法,我可以在管道上使用它。然而,经过进一步测试,即使最后一个也出现了管道上的输出拥塞问题。
-
是 db/querystore 特定,还是您尝试为多个后端存储创建抽象层?很多数据库引擎已经有了 SDK 来处理抽象这些东西
-
@MathiasR.Jessen 在多个数据库引擎 SDK 之上的一个通用对象抽象层。最好将 CSV 查询参数通过管道传输到知道使用哪个 SDK 将结果放入输出文件的连接中。使用流水线有助于将 RAM 内开销保持在足够低的水平以提取结果。我也许可以将其转换为 cmdlet,这可能是我需要进一步深入研究的内容。
标签: powershell pipeline powershell-5.0 pscustomobject