0

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()}
}

虽然这似乎是一个功能模型,但如果有一个解决方案不需要连接对象的用户每次使用对象的方法时都必须在他们的末端编写开始/处理/结束脚本,那就更好了.

4

1 回答 1

1

几天后,咖啡喝多了;我想我在这里学到的是,如果可以,请尝试将其重构为一个好的旧的直接高级函数/cmdlet

$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)"
   }
}
filter Write-PassThru{
   write-host $_ -ForegroundColor Cyan
   $_
}
$InvObj = [PSCustomObject]@{
   PSTypeName    = 'Data.Connection'
   con           = 'item.inventory'
   FetchItemData = 'Get-ItemData'
}

function Get-ItemData{
   param(
      [parameter(mandatory=$true)]
      [PSTypeName('Data.Connection')]
      $t,
      
      [bool]
      $Header=$true,
      
      [Parameter(ValueFromPipeline=$true)]
      $itm
   )
   begin{
      $query   = 'select * from inventory where item = ?'
      $qHeader = 'Item;Location;Quantity'
      $param   = $null

      write-host "connect to: $($t.con)"
      write-host "compile command: $query"
      $param = $QueryParameter
      write-host 'begin transaction'
      if($Header){
         "   $qHeader" | write-passthru
      }
   }process{
      $param.Value = $itm
      MockDataQuery | write-passthru
   }end{
      write-host 'end transaction'
      write-host 'dispose command'
      write-host 'close connection'
   }
}

1..5                        `
   | %{"ItemNo$_"}          `
   | &$InvObj.FetchItemData $InvObj

但是,如果你不能,你也可以尝试做一些像这样非常hacky的事情
$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)"
   }
}
filter Write-PassThru{
   write-host $_ -ForegroundColor Cyan
   $_
}
$InvObj = [PSCustomObject]@{
   PSTypeName    = 'Data.Connection'
   con           = 'item.inventory'
   FetchItemData = {
      param(
         [bool]
         $Header=$true,
         
         [Parameter(ValueFromPipeline=$true)]
         $itm
      )
      begin{
         $pm = $MyInvocation.PositionMessage -split "`n"
         [int]$at = $pm[0] -replace '.*char:(\d+).*','$1'
         $l = ($pm[2] -replace '[^~]','').Length
         $myCall = $pm[1].substring($at+1,$l)
         $thus = get-variable -Name ($myCall -replace '.*?\${?([^}.]+)}?\..*','$1') -ValueOnly

         $query   = 'select * from inventory where item = ?'
         $qHeader = 'Item;Location;Quantity'
         $param   = $null

         write-host "connect to: $($thus.con)"
         write-host "compile command: $query"
         $param = $QueryParameter
         write-host 'begin transaction'
         if($Header){
            "   $qHeader" | write-passthru
         }
      }process{
         $param.Value = $itm
         MockDataQuery | write-passthru
      }end{
         write-host 'end transaction'
         write-host 'dispose command'
         write-host 'close connection'
      }
   }
}

function Annotate-Flow{
   param(
      [string]
      $tag = 'Flow',
      
      [switch]
      $head,
      
      [switch]
      $tail
   )
   begin{
      if($head){
         $Global:FlowSequence = 0
      }else{$Global:FlowSequence++}
      write-host ("${Tag} Seq[{0,2}]: Begin" -f $Global:FlowSequence) -ForegroundColor DarkCyan
   }process{
      $Global:FlowSequence++
      write-host ("${Tag} Seq[{0,2}]: Process($_)" -f $Global:FlowSequence)-ForegroundColor DarkCyan
      $_
   }end{
      $Global:FlowSequence++
      write-host ("${Tag} Seq[{0,2}]: End" -f $Global:FlowSequence) -ForegroundColor DarkCyan
      if($tail){
         remove-variable -Scope Global -Name FlowSequence
      }
   }
}

1..5                        | Annotate-Flow Source -head `
   | %{"ItemNo$_"}          | Annotate-Flow Format       `
   | &$InvObj.FetchItemData | Annotate-Flow Lookup -tail

一些你可能(不想)想读的东西:

虽然,老实说,这感觉更像是一个凑合的答案,而不是一个优雅的解决方案。

于 2021-02-19T01:52:43.540 回答