MSBuild: 阶乘!





4.00/5 (1投票)
使用 MSBuild 目标作为通用函数,带有参数和返回值
我一直在探索 MSBuild 作为一种编程语言。关于可变性/不可变性有一些有趣的结果,但那是另一篇博文的内容。
这篇博文是关于函数的。特别是,可以使用 MSBuild 任务调用目标,所以我正在探索将目标用作函数。MSBuild 可以通过发送属性将参数传递给目标。但是,属性更改不会传播回调用者,因此获取返回值会比较棘手。
事实证明,MSBuild 确实从目标返回一条信息:它的输出。可以将目标的输出设置为属性,并让该目标依赖于设置该属性的另一个目标。通过这种方式,可以创建一对可以“计算”外部目标输出的目标。
通过结合这些方法(为参数设置属性,并将目标的输出用作返回值),可以将目标视为函数。
为了演示,我编写了这个程序,它使用 MSBuild 递归地计算属性 $(Input)
的阶乘。尽情玩耍吧!
<Project ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<!-- Factorial program using MSBuild recursively -->
<Target Name="Default">
<!-- Display usage -->
<Error Condition="'$(Input)' == ''"
Text="Usage: msbuild factorial.proj [/nologo] [/clp:v=minimal] /p:Input=nnn"/>
<!-- Argument error checking -->
<MSBuild.ExtensionPack.Science.Maths TaskAction="Compare"
P1="$(Input)" P2="1" Comparison="LessThan">
<Output TaskParameter="LogicalResult" PropertyName="InputCheck"/>
</MSBuild.ExtensionPack.Science.Maths>
<Error Condition="'$(InputCheck)' != 'False'"
Text="Input cannot be less than 1."/>
<!-- Invoke the Factorial target with the current Input property -->
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="Factorial" Properties="Input=$(Input)">
<Output TaskParameter="TargetOutputs"
ItemName="FactorialResult"/>
</MSBuild>
<!-- Display the result -->
<Message Importance="high" Text="Result: @(FactorialResult)"/>
</Target>
<!-- The Factorial target uses FactorialCore to do the calculation,
storing the result in FactorialResult -->
<Target Name="Factorial"
DependsOnTargets="FactorialCore" Outputs="$(FactorialResult)" />
<Target Name="FactorialCore">
<!-- If the input is 1, then the factorial is 1 -->
<PropertyGroup Condition="'$(Input)' == '1'">
<FactorialResult>1</FactorialResult>
</PropertyGroup>
<!-- If we don't know the result yet
(i.e., the input is not 1), then calculate the factorial -->
<CallTarget Condition="'$(FactorialResult)' ==
''" Targets="CalculateFactorial"/>
</Target>
<Target Name="CalculateFactorial">
<!-- Subtract 1 from $(Input) -->
<MSBuild.ExtensionPack.Science.Maths TaskAction="Subtract" Numbers="$(Input);1">
<Output TaskParameter="Result" PropertyName="InputMinus1"/>
</MSBuild.ExtensionPack.Science.Maths>
<!-- Determine the factorial of $(Input) - 1 -->
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="Factorial" Properties="Input=$(InputMinus1)">
<Output TaskParameter="TargetOutputs" ItemName="SubResult"/>
</MSBuild>
<!-- Multiply !($(Input) - 1) by $(Input) to get the result-->
<MSBuild.ExtensionPack.Science.Maths TaskAction="Multiply"
Numbers="@(SubResult);$(Input)">
<Output TaskParameter="Result" PropertyName="FactorialResult"/>
</MSBuild.ExtensionPack.Science.Maths>
</Target>
<!-- Maybe I just have way too much time on my hands... -->
</Project>
msbuild factorial.proj /nologo /clp:v=minimal /p:Input=5
默认值
结果:120
msbuild factorial.proj /nologo /clp:v=minimal /p:Input=7
默认值
结果:5040
没用,但仍然很酷。