65.9K
CodeProject 正在变化。 阅读更多。
Home

MSBuild: 阶乘!

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2009年6月20日

公共领域

1分钟阅读

viewsIcon

26382

使用 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

没用,但仍然很酷。

© . All rights reserved.