It's been a while since I've updated this.  My apologies, but I do tend to disappear from work for the month of December, which is what I did this year too.  Happy 2007!

 

This article can be considered somewhat of a sequel to my last one (CodeDom Quirks), but now I'll focus on some quirkiness of the WF Rules expression editors.  The same editor is used to author and edit both Declarative Rule Conditions (the Condition editor) as well as Rule conditions and actions (the RuleSet editor).  Both support a natural algebraic expression language that parses a large subset of what C# can express.

 

As I mentioned in the previous article, the parser behind these designers consumes an expression and translates into an expression object model used by WF Rules, namely CodeDom.  Thus if you enter the following into the condition editor:

 

2 + 3 == 5

 

the editor parses this and saves it as a CodeDom tree, just as if you had created the following CodeDom tree yourself:

 

new CodeBinaryOperatorExpression(

    new CodeBinaryOperatorExpression(

        new CodePrimitiveExpression(2),

        CodeBinaryOperatorType.Add,

        new CodePrimitiveExpression(3)),

    CodeBinaryOperatorType.ValueEquality,

    new CodePrimitiveExpression(5))

 

This CodeDom is then serialized out to the .rules file, where you can see that it shows up just as XML serialized CodeDom.  Note that the original text (2+3==5) was never saved.  When you re-edit the expression (in fact, as soon as you press <TAB> in the dialog), the CodeDom is decompiled back into a canonical string form.  It turns out that this is the source of many of the "quirks" described in this article, because the decompile may not preserve the exact syntax you wrote.

 

SPACING

 

At its most basic level, this decompilation process will strip out any excess spaces, or add spaces.  For example:

 

2+      3               ==5

 

will simply end up being decompiled as:

 

2 + 3 == 5

 

That's fairly innocuous, but there are a few instances where the canonical form may surprise you (and I admit, there are times when it may annoy you).

 

PARENTHESES

 

The decompilation uses the minimum amount of parenthesization necessary to preserve operator precedence.  Thus if you enter the following into the condition editor:

 

((2 - 3) + 4) == 3

 

and hit <TAB>, your expression will be replaced by:

 

2 - 3 + 4 == 3

 

All the parentheses disappear because they're all redundant.

 

ZERO MINUS

 

Remember in the last article when I said the unary negation operator was not supported by CodeDom.  No problem, the expression editor will still parse "-x" and turn it into "0 - x".  The decompilation is even smart enough to show "0 - x" as "-x".  Pretty smart, eh?  However, if you enter the following into the condition editor:

 

3 + (0 - 5) == (0 - 2)

 

and hit <TAB>, your expression will be rewritten as:

 

3 + -5 == -2

 

The "pretty smart" decompilation really can't tell whether you typed "0 - 5" or whether you typed "-5" because they're both represented by the same CodeDom tree.

 

I do like to think that the canonical form is simpler in this case.

 

EQUAL FALSE

 

Similarly, recall that CodeDom does not support a unary NOT operation.  The expression editor still parses "!x" and turns it into "x == false".  Once again the decompilation is smart enough to show "x == false" as "!x".  But once again, if you entered:

 

(2 > 5) == false

 

and hit <TAB>, your expression will be rewritten as:

 

!(2 > 5)

 

This may or may not be more readable depending on your taste, but it is the canonical representation of the "== false" pattern.  Note that if you'd entered:

 

(2 == 5) == false

 

the decompilation would be even smarter and rewrite this as:

 

2 != 5

 

which is, in my opinion, a much simpler expression.

 

ALTERNATE OPERATOR SPELLINGS

 

To make the condition editor's expression language more approachable to a wider audience of developers, we chose to support some alternate operator spellings.  Most of these alternate spellings come from VB.  So instead of "!=" you can use "<>".  Instead of unary "!" you can use "NOT".  Here's a complete list:

 

  • Inequality:  !=  <>
  • Unary NOT:  !    NOT
  • Boolean AND:  &&  AND
  • Boolean OR:  ||   OR
  • Modulus:  %   MOD
  • This reference:  this   me
  • Null reference:  null   nothing

 

However, only the operator spellings in bold will be preserved by the decompilation.  Thus, if you type:

 

me.x <> 5 AND me.y == nothing

 

and hit <TAB>, the expression will get rewritten to:

 

this.x != 5 && this.y == null

 

This may definitely fall into the category of "annoying", but simply reflects our teams C# bias.  My apologies to all esteemed VB'ers out there.

 

QUALIFIED TYPE NAMES

 

The expression editor will allow you to refer to unqualified type names as long as they have unambiguous names.  For example, if you have types "Foo.Glorp" and "Bar.Glorp", you cannot unambiguously refer to the type as "Glorp"; you have to use the fully qualified type name.  On the other hand the type "Console" refers unambiguously to "System.Console", so you can refer to it just as "Console".

 

The decompilation does not know what type names are unique, so it always fully-qualifies them.  Thus if you type:

 

DateTime.Now.Year == 2007

 

and press <TAB>, this will get rewritten as:

 

System.DateTime.Now.Year == 2007

 

EXPLICIT "THIS" QUALIFICATION

 

Like C#, the expression editor will allow you to refer to an instance member of the "ambient" class without qualifying it with "this.".  In a workflow application, the ambient class is always the root workflow class.  If your workflow type has an instance field "int foo", you can enter the following expression in the editor:

 

foo > 25

 

However, when you press <TAB>, the canonicalized representation will be decompiled as:

 

this.foo > 25

 

We chose to be explicit about "this." qualification because unlike an instance method within a C# class, it is not obvious what the ambient class is.  Making "this." qualification explicit helps make developers aware of the context in which they are accessing data.

 

SUMMARY

 

If you use the WF Rules expression editor enough, you may run into other CodeDom decompilation "quirks" that I have not mentioned.  By all means let me know if you find anything else surprising and/or annoying.