我正在尝试为PowerShell函数添加一些回调功能,但我希望能够在函数定义之外定义回调的行为,所以基本上是一个非常简单的PowerShell控制反转。
我正在尝试尽可能向后兼容,这是我到目前为止所提出的(为简洁起见,错误处理已被删除):
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";
function Invoke-DoSomethingMethod
{
param
(
[hashtable] $Callbacks
)
$CallBacks["OnStarted"].Invoke();
for( $i = 1; $i -le 10; $i++ )
{
# ... do something here ...
$CallBacks["OnProgress"].Invoke($i * 10);
}
$CallBacks["OnFinished"].Invoke();
}
$myHostCallbacks = @{
"OnStarted" = { write-host "started" }
"OnProgress" = { write-host "processing $($args[0])%" }
"OnFinished" = { write-host "finished" }
}
$myFileCallbacks = @{
"OnStarted" = { Add-Content "C:\temp\log.txt" "started" }
"OnProgress" = { Add-Content "C:\temp\log.txt" "processing $($args[0])%" }
"OnFinished" = { Add-Content "C:\temp\log.txt" "finished" }
}
$myWebCallbacks = @{
"OnStarted" = { Invoke-WebRequest -Uri "http://example.org/OnStarted" }
"OnProgress" = { Invoke-WebRequest -Uri "http://example.org/OnProgress/$($args[0])" }
"OnFinished" = { Invoke-WebRequest -Uri "http://example.org/OnFinish" }
}
Invoke-DoSomethingMethod -Callbacks $myHostCallbacks;
运行时,输出以下内容:
c:\temp>powershell .\callbacks.ps1
started
processing 10%
processing 20%
processing 30%
processing 40%
processing 50%
processing 60%
processing 70%
processing 80%
processing 90%
processing 100%
finished
在不使用外部模块或C#代码的情况下,是否有一种更为自觉的方式使用PowerShell,而不依赖于匹配回调名称的魔术字符串和$ args []参数的顺序? (优先与2.0版兼容)。
干杯,
麦克
更新
对于某些上下文,我的Invoke-DoSomething函数是CI构建框架的一部分 (https://github.com/ASOS/OctopusStepTemplateCi)当前是硬编码的,用于在构建过程中使用Write-Host发送TeamCity服务消息。
我们有兴趣支持其他构建服务器产品,因此我正在研究一种方法,将与构建服务器的各种交互抽象为用户可定义的回调,如“OnBuildStarted”,“OnBuildStepFailed”等,就像你可能做的那样使用C#中的IoC框架。
这样可以更轻松地从项目内部为新的构建服务器提供支持,也可以让用户为不是开箱即用的构建服务器编写回调。
这可能有助于说明我正在尝试做的事情:
function Invoke-BuildScript
{
param( [hashtable] $Callbacks )
$CallBacks["OnBuildStarted"].Invoke();
... build script here ...
$CallBacks["OnBuildFinished"].Invoke();
}
$teamCityCallbacks = @{
"OnBuildStarted" = { write-host "started" }
"OnBuildFinished" = { write-host "finished" }
"OnBuildError" = { write-host "error '$($args[0])'" }
}
$jenkinsCallbacks = @{
"OnBuildStarted" = { ... }
"OnBuildFinished" = { ... }
"OnBuildError" = { ... }
}
Invoke-BuildScript -Callbacks $teamCityCallbacks;
答案 0 :(得分:2)
与我在PowerShell中关于IoC的原始问题的答案不同,但我设法至少隐藏了一些包装器cmdlet背后的魔术字符串和回调参数,因此回调结构变为不透明类型:
# knowledge of magic strings and parameter orders confined to here
function Invoke-OnStartedCallback
{
param
(
[hashtable] $Callbacks
)
Invoke-Callback -Callbacks $CallBacks -Name "OnStarted";
}
function Invoke-OnProgressCallback
{
param
(
[hashtable] $Callbacks,
[int] $PercentComplete
)
Invoke-Callback -Callbacks $CallBacks -Name "OnProgress" -Parameters @( $PercentComplete );
}
function Invoke-OnFinishedCallback
{
param
(
[hashtable] $Callbacks
)
Invoke-Callback -Callbacks $CallBacks -Name "OnFinished";
}
function New-DoSomethingCallbacks
{
param
(
[scriptblock] $OnStarted,
[scriptblock] $OnProgress,
[scriptblock] $OnFinished
)
return @{
"OnStarted" = $OnStarted
"OnProgress" = $OnProgress
"OnFinished" = $OnFinished
};
}
其余代码可以写成:
# no knowledge of magic strings below here
function Invoke-DoSomethingMethod
{
param
(
[hashtable] $Callbacks
)
Invoke-OnStartedCallback $CallBacks;
for( $i = 1; $i -le 10; $i++ )
{
# ... do something ...
Invoke-OnProgressCallback $CallBacks -PercentComplete ($i * 10);
}
Invoke-OnFinishedCallback $CallBacks;
}
$myHostCallbacks = New-DoSomethingCallbacks -OnStarted { write-host "started" } `
-OnProgress { write-host "processing $($args[0])%" } `
-OnFinished { write-host "finished" };
$myFileCallbacks = New-DoSomethingCallbacks -OnStarted { Add-Content "C:\temp\log.txt" "started" } `
-OnProgress { Add-Content "C:\temp\log.txt" "processing $($args[0])%" } `
-OnFinished { Add-Content "C:\temp\log.txt" "finished" };
$myWebCallbacks = New-DoSomethingCallbacks -OnStarted { Invoke-WebRequest -Uri "http://example.org/OnStarted" } `
-OnProgress { Invoke-WebRequest -Uri "http://example.org/OnProgress/$($args[0])" } `
-OnFinished { Invoke-WebRequest -Uri "http://example.org/OnFinish" };
Invoke-DoSomethingMethod -Callbacks $myHostCallbacks;
使用小帮助cmdlet:
function Invoke-Callback
{
param
(
[hashtable] $Callbacks,
[string] $Name,
[object[]] $Parameters
)
if( -not $Callbacks.ContainsKey($Name) )
{
return;
}
$callback = $Callbacks[$Name];
if( $null -eq $callback )
{
return;
}
if( $null -eq $Parameters )
{
$callback.Invoke();
}
else
{
$callback.Invoke($Parameters);
}
}
答案 1 :(得分:0)
不确定以下是否符合您的要求。也许我也误解了这个问题。
function Invoke-DoSomethingMethod ($OnStarted, $OnProgress, $OnFinished) {
Invoke-Command -ScriptBlock $OnStarted
for ( $i = 1; $i -le 10; $i++ ) {
Invoke-Command -ScriptBlock $OnProgress
}
Invoke-Command -ScriptBlock $OnFinished
}
$OnStartedSb = [ScriptBlock]::Create('write-host "started"')
$OnProgressSb = [ScriptBlock]::Create('write-host "processing $($i * 10)%"')
$OnFinishedSb = [ScriptBlock]::Create('write-host "finished"')
Invoke-DoSomethingMethod -OnStarted $OnStartedSb -OnProgress $OnProgressSb -OnFinished $OnFinishedSb