Reputation: 12516
I need to extend the current value of DefineConstants
property of my csproj
-file. The string, which I want to add as a suffix, can be evaluated on C# such:
Int32 min_year = 2009;
Int32 max_year = 2015;
String result = String.Join(";", Enumerable.Range(min_year, max_year -
min_year + 1).Select(n=>"NEWER_THAN_AUTOCAD_" + (n - 1)).ToArray());
// result:
// NEWER_THAN_AUTOCAD_2008;NEWER_THAN_AUTOCAD_2009;
// NEWER_THAN_AUTOCAD_2010;NEWER_THAN_AUTOCAD_2011;
// NEWER_THAN_AUTOCAD_2012;NEWER_THAN_AUTOCAD_2013;
// NEWER_THAN_AUTOCAD_2014
I need to do the same logic in the MSBuild code... I try to do it through this way:
$([System.String]::Join(`;`,[System.Linq.Enumerable]::Range(2009,[MSBuild]::Add(
[MSBuild]::Subtract($(CAD_Year),2009),1)).Select(n=>[System.String]::Concat(
"NEWER_THAN_AUTOCAD_"),[MSBuild]::Subtract(n,1).ToArray()))
But I get this expression in the DefineConstants
property instead of evaluated value. How can I fix it?
Upvotes: 1
Views: 3354
Reputation: 531
First of all: count your brackets :P There is one missing on the end. (but this is irrelevant)
Secondly: If you want to 'execute' some special function, you have to use $()
every time, not only the first. So this is incorrect:
<PropertyGroup>
<MyDefineConstants>$([System.String]::Join(';',[System.Linq.Enumerable]::Range(2009,2012)))</MyDefineConstants>
</PropertyGroup>
this is correct
<PropertyGroup>
<MyDefineConstants>$([System.String]::Join(';',$([System.Linq.Enumerable]::Range(2009,2012))))</MyDefineConstants>
</PropertyGroup>
But... namespace System.Linq.Enumerable is not available in MsBuld. You cannot use every namespace you want. This is for safety reasons. If you really want to use this, you will have to set the environment variable MSBUILDENABLEALLPROPERTYFUNCTIONS=1. But I don't recommend this.
If you want learn more: try MSBuild Property Functions on The Visual Studio Blog
Apart from the above: Select
method is NOT real method. Ok, it is, but not that kind you normally invoke by writing myobject.method()
. This is the Extension Methods.
This is only syntactic-sugar. And when you write Enumerable.Range(1, 5).Select(n => n*2)
and compiler invoke the method like this Enumerable.Select(Enumerable.Range(1, 5), n => n*2)
- and this is how you should invoke it.
Ok, enough babbling... I think the simples way is the best... so
<ItemGroup>
<CadYear Include="2009" />
<CadYear Include="2010" />
<CadYear Include="2011" />
<CadYear Include="2012" />
<CadYear Include="2013" />
</ItemGroup>
<PropertyGroup>
<DefineConstants>@(CadYear->'NEWER_THAN_AUTOCAD_%(Identity)')</DefineConstants>
</PropertyGroup>
You still have to set the year, so I think it could not be a downside if you have to define all years :P
Or... if you are really find 'clean'/'complex' solution. You just can write Inline Task. Then you can write what ever you want and what ever complex code you can think of in C#.
Upvotes: 3