-
Notifications
You must be signed in to change notification settings - Fork 11
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 BlockExpressions 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
'BlockExpressions 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
'