-
Notifications
You must be signed in to change notification settings - Fork 12
BlockExpression rendering in C# and Visual Basic renderers
BlockExpression
allows putting multiple expressions where previously only a single expression would have been allowed. This allows constructing expression trees with multiple statements, like the following:
if (DateTime.Now.Hour < 18) {
Console.WriteLine("Good day");
Console.WriteLine("Have a nice day");
} else {
Console.WriteLine("Good night");
Console.WriteLine("Have a nice night");
}
via factory methods:
var writeline = typeof(Console).GetMethods("WriteLine", new [] { typeof(string) });
Expression expr = IfThenElse(
LessThanOrEqual(
Property(
Property(null, typeof(DateTime).GetProperty("Now")),
"Hour"
),
Constant(18)
),
// the following two Block calls each produce a BlockExpression
Block(
Call(writeline, Constant("Good day!")),
Call(writeline, Constant("Have a nice day!"))
),
Block(
Call(writeline, Constant("Good night!")),
Call(writeline, Constant("Have a nice night!"))
)
);
Since BlockExpression
is an expression like any other, it could theoretically be put in places where C# And VB.NET don't allow it, such as in the test of an if...else
block:
if ({
true;
true;
}) {
Console.WriteLine(true);
}
The following sections describe how BlockExpression
is rendered in the C# and Visual Basic renderers.
When an inline expression is expected (such as in a ternary if, or some binary operation), a BlockExpression
is rendered using parentheses and a C-style comma operator:
() => (
true,
true
) ? true : false
which has precisely equivalent semantics to the BlockExpression
-- multiple sub-expressions are supported, but the value of the entire expression is the value of the last sub-expression.
The comma operator is also used for BlockExpression
s in a test clause, such as the test of an if (...) {...}
block:
if (
true,
true
) {
Console.WriteLine(true);
}
BlockExpressions
which appear when a given syntax expects a block is expected are rendered with curly braces and semicolons (when needed):
if (true) {
Console.WriteLine(true);
Console.WriteLine(true);
}
A BlockExpression
whose parent is another BlockExpression
will not be rendered as a separate block:
// using static System.Linq.Expressions.Expression;
// using ExpressionToString;
var writeline = typeof(Console).GetMethods("WriteLine", new Type[] { });
Expression expr = Block(
Call(writeline),
Block(
Call(writeline),
Call(writeline)
),
Call(writeline)
);
Console.WriteLine(expr.ToString("C#"));
/*
(
Console.WriteLine(),
Console.WriteLine(),
Console.WriteLine(),
Console.WriteLine()
)
*/
unless the inner BlockExpression
introduces variables into the local scope:
// using static System.Linq.Expressions.Expression;
// using ExpressionToString;
var writeline = typeof(Console).GetMethods("WriteLine", new Type[] { });
Expression expr = Block(
Call(writeline),
Block(
new[] { Parameter(typeof(string), "s1") },
Call(writeline),
Call(writeline)
),
Call(writeline)
);
Console.WriteLine(expr.ToString("C#"));
/*
(
Console.WriteLine(),
(
string s1,
Console.WriteLine(),
Console.WriteLine()
),
Console.WriteLine()
)
*/
Note that within the comma operator, statements such as variable declaration (if (string s1, true)
), are not valid C# syntax.
For syntactic structures which expect a block of statements, the BlockExpression
is rendered only as its individual statements:
'Imports System.Linq.Expressions.Expression
'Imports ExpressionToString
Dim writeline = GetType(Console).GetMethods("WriteLine", { })
Dim expr = IfThen(
Constant(True),
Block(
[Call](writeline),
[Call](writeline)
)
)
Console.WriteLine(expr.ToString("Visual Basic"))
'
' If True Then
' Console.WriteLine
' Console.WriteLine
' End If
'
BlockExpression
s in an inline position are rendered using (the non-existent) Block...End Block
syntax:
'Imports System.Linq.Expressions.Expression
'Imports ExpressionToString
Dim writeline = GetType(Console).GetMethods("WriteLine", { })
Dim blockExpr = Block(
Constant(True),
Constant(True)
)
Dim expr = [AndAlso](
blockExpr,
blockExpr
)
Console.WriteLine(expr.ToString("Visual Basic"))
'
' Block
' True
' True
' End Block AndAlso Block
' True
' True
' End Block
'
The statements in a nested BlockExpression
are rendered without any indication of the BlockExpression
, only alongside the parent statements:
Dim expr = IfThen(
Constant(True),
Block(
Constant(True),
Block(
Constant(True),
Constant(True)
),
Constant(True)
)
)
Console.WriteLine(expr.ToString("Visual Basic"))
'
' If True Then
' True
' True
' True
' True
' End If
'
unless local variables are introduced in the nested block, in which case the nested block is marked with Block....End Block
:
Dim expr = IfThen(
Constant(True),
Block(
Constant(True),
Block(
{Parameter(GetType(String), "s1")},
Constant(True),
Constant(True)
),
Constant(True)
)
)
Console.WriteLine(expr.ToString("Visual Basic"))
'
' If True Then
' True
' Block
' Dim s1 As String
' True
' True
' End Block
' True
' End If
'