38

Since I have only seen a few posts on the topic but no in-depth explanation of the logic for parameters in templates for Visual Studio, I figured I'd post this here.

Following the MSDN article you can add custom parameters to your template that can be altered with a Wizard if you want to alter them.

In any file of the template (other than the template file itself) you can add logic based on the parameters. There are only three keywords to be used with the logic. $if$ ( %expression% ), $else$, and $endif$. So say I have the following in a template file:

public string foo( string a )
{
    return string.Format( @"foo( {0} );", a );
}

And we want to add some logic for whether or not we want to check if "a" is null or empty

public string foo( string a )
{
$if$ ( $shouldCheckForNullOrEmpty$ == true )
    if ( !string.IsNullOrEmpty( a ) )
$endif$

    return string.Format( @"foo( {0} );", a );
}

Of course you may want to add the braces for the if statement so you may need more than one logic block.

So that is not too bad, but there are a few tricks to this. The $if$ check for string match, that is shouldCheckForNullOrEmpty must equal "true". It was also tempted in writing $if$ ($shouldCheckForNullOrEmpty$ == "true"), but that will not work.

Single if statements with single expressions are pretty simple so now for a bit more complex example:

public string foo( string a )
{
$if$ ( $parameterCheckMode$ == ifNullOrEmpty )
    if ( !string.IsNullOrEmpty( a ) )
$else$ $if$ ( $parameterCheckMode$ == throwIfNullOrEmpty )
    if ( string.IsNullOrEmpty( a ) )
        throw new ArgumentException();
$endif$ $endif$

    return string.Format( @"foo( {0} );", a );
}

As you may be able to tell, this is a switch statement for the parameter mode. You may note that there is no $elseif$ so you have to make it $else$ $if$ but will have to add an extra $endif$ at the end.

Lastly, I have yet to find and or or symbols for the logic. I got around this by just using the logic equivalence:

and -> $if$ ( expression1 ) $if$ ( expression2 ) $endif $endif$

or -> $if$ ( expression1 ) statement $else$ $if$ statement $endif$ $endif$

Hopefully this helps someone.

maschall
  • 988
  • 1
  • 7
  • 13
  • 6
    The question is -- why are you forcing yourself to use the project template mechanism to perform this sort of conditionals ? Templates exist for a basic starting point that is pretty constant, and not for the purpose of creating complex classes with logic based on user supplied options (this is very hard to maintain). – lysergic-acid Jul 16 '11 at 10:01
  • What versions of Visual Studio have you tested this with? I've been fighting with it in Visual Studio 2008, and while $parameter$ replacement works just fine, the $if$/$else$/$endif$ keywords seem to be completely ignored. If I put in something like "$if$ ($targetframeworkversion$ == 3.5)using System.Linq;$endif$", I get out "$if$ (3.5 == 3.5)using System.Linq;$endif$". – Sean Werkema Mar 07 '12 at 01:27
  • After a lot of research, this does work in Visual Studio 2008, but it's very quirky and requires a "magic" XML directive in the `.vstemplate` file: ``. Notice the critical `3.0.0` in there. There are a lot of other quirks surrounding whitespace in the templates, too; more info can be found in this thread: http://stackoverflow.com/questions/1220389/whats-wrong-with-my-visual-studio-2008-template/1568717 – Sean Werkema Mar 07 '12 at 02:41
  • You should have written this in a question / answer format to assist people searching for a question. – HankCa Dec 19 '17 at 00:43
  • I've been unable to find a 'not'. The workaround I've used is to either live on the "$else$" or simply make parameter strings that are "false/no" etc. – Xenial Apr 04 '18 at 10:31
  • I also find that while $if$, $else$, and $endif$ work fine, they always break when I try to nest anything. Eg (VS2017): $if$ ($SolutionPropsSheetRelativePath$ == fog) $if$ ($CommonPropsSheetRelativePath$ == ) $else$ $endif$ $else$ $endif$ ...outputs what should be impossible: – Xenial Apr 04 '18 at 12:57
  • I’m voting to close this question because it is not a question. – svick Dec 11 '20 at 14:37

2 Answers2

1

This post is linked from the official Microsoft documentation for MSBuild Conditions as having examples of usage. The syntax for MSBuild conditions is not exactly equivalent to the way templating $if$ statements work but it's a close approximation. However, it seems the examples here are now obsolete or were never completely accurate to begin with. After some extensive testing I have found the following to be true in regards to templating $if$ statements:

$if$ statements can never be nested. The reason for this is the way in which the templating engine handles the case of an $if$ statement evaluating to false. When an $if$ expression evaluates to false the engine will parse until the next $endif$ it finds and remove everything in between. This means when there is a nested $if$ statement, that will be the first $endif$ that is reached and the nested $if$ expression will be removed before processing. The same is true when using $else$. There are a few misleading examples in the "question" above that will only work in the case that the outer $if$ statement evaluates to true. Consider the following example where the outer $if$ statement does not evaluate to true:

public void foo()
{
    string str = "";

    $if$ ($true$ == false)
    str = "foo";

    $if$ ($true$ == true)
    str = str + "bar";
    $endif$ //inner

    $endif$ //outer

    return str;
}

The result of running this template would be the following:

public void foo()
{
    string str = "";

    //inner

    $endif$ //outer

    return str;
}

As you can see, everything after the first $endif$ is left in the code. I've come up with a suitable workaround that involves using a combination of the & operator and serial if statements.

There is a logical & operator that can be used within a single if statement. The syntax is as follows:

$if$ ($foo$|$bar$ == true|false)

This will evaluate as $foo$ == true && $bar$ == false. It is valid to use more than two operands, e.g. $foo$|$bar$|$baz$|... == true|false|etc|.... The caveat to this usage is that you can only use a single operator type for all comparisons in the statement (==|!= is not valid). I was unable to find anything comparable to an Or operator.

Putting it all together. The & operator can be used with a series of if statements to create a simulated nested-if environment. The following example shows 3 levels of nesting if(foo){...if(bar){...if(baz){...}...}...}:

public void foo()
{
    string str = "";

    $if$ ($ext_foo$ == true)
    str = "foo";
    $endif$$if$ ($ext_foo$|$ext_bar$ == true|true)
    str = str + "bar";
    $endif$$if$ ($ext_foo$|$ext_bar$|$ext_baz$ == true|true|true)
    str = str + "baz";
    $endif$$if$ ($ext_foo$|$ext_bar$ == true|true)
    str = str + "bar";
    $endif$$if$ ($ext_foo$ == true)
    str = str + "foo";
    $endif$

    return str;
}
0

For the logic and and or
and is:
&&
while or is:
||

So, an if statement with and in it would look like this:

if ((a != null)&&(a !=""))
{
    Console.Write(a);
}

And an if statement with or in it would look like this:

if ((b != null)||(b >= 5))
{
    Console.Write(b);
}

For the template, you could Export a *.cs file as a template. It is under Project>Export Template...

(I was using VisualStudios 2017)

Hopes this helps.

t3m2
  • 366
  • 1
  • 15
Harry S
  • 985
  • 5
  • 6