Can I generate an async method dynamically using System.Linq.Expressions? - c#

I know the compiler can't convert an async lambda expression to an expression tree, but is it possible to generate the expression tree manually ?
var expr = Expression.Lambda<Func<Task>>(
// how do I use 'await' in the body here?
);
var func = expr.Compile();
I can't find any method related to async or await in the Expression class, but perhaps there's another way?

await involves significant compiler re-writing; the generated IL is quite dissimilar to the original C#, with variable hoisting (onto a class) and branching, tasks, continuations, etc. It certainly isn't something that can be represented in a simple lambda, although in recent versions of .NET with richer Expression support (Expression.Block etc), technically I suppose it is probably possible to mimic most of the things the compiler does for await - but you'd probably go quite loopy trying to do it by hand.
No, AFAIK, no facility to automate this translation exists in the Expression API, and frankly I wouldn't ever expect there to be.
The same probably could be say of ILGenerator; frankly, AFAIK the only "easy" way (and I use the word "easy" quite incorrectly) to use await in meta-programming would be to generate C# and run it through roslyn or CSharpCodeProvider.

Late to the party, but I just published a lib which does accomplish this.
https://github.com/avonwyss/bsn.AsyncLambdaExpression
It leverages the fact that nested Lambdas in an Expression Tree can access the outer lambda variables (which are captured as closure, just like nested lambdas behave in C#). Thus the code creates a main lambda containing all the necessary variables and returning a Task, and a state machine in a nested lambda which is callable as continuation on awaiter.OnComplete(). Since the state, current awaiter etc. is stored in the closure, the state machine keeps its state even when the inner lambda stops execution.
The API to use it consists of two extension methods, one for awaiting and one for converting the Expression Tree with await to a lambda implementing the state machine and returning the Task.
Here's a code sample:
// Build a normal expression tree with "await" calls
var paraInput = Expression.Parameter(typeof(string), "input");
var exprTree = Expression.Lambda<Func<Task<string>, string>>(
Expression.Block(
Expression.Call(typeof(Task), nameof(Task.Delay), null, Expression.Constant(1000)).Await(false),
paraInput.Await(false)),
paraInput);
// Create compilable state machine async expression tree (result must be Task<?> or Task)
var asyncExprTree = exprTree.Async<Func<Task<string>, Task<string>>>();
var asyncCompiled = asyncExprTree.Compile();
// Invoke delegate as usual
var result = await asyncCompiled(Task.FromResult("test")).ConfigureAwait(false);
The DebugView of the original lambda Expression Tree is like this:
.Lambda #Lambda1<System.Func`2[System.Threading.Tasks.Task`1[System.String],System.String]>(System.Threading.Tasks.Task`1[System.String] $input)
{
.Block() {
.Call bsn.AsyncLambdaExpression.AsyncExpressionExtensions.AwaitVoid(.Call (.Call System.Threading.Tasks.Task.Delay(1000)).ConfigureAwait(False));
.Call bsn.AsyncLambdaExpression.AsyncExpressionExtensions.AwaitResult(.Call $input.ConfigureAwait(False))
}
}
The async conversion creates the following Expression Tree:
.Lambda #Lambda1<System.Func`2[System.Threading.Tasks.Task`1[System.String],System.Threading.Tasks.Task`1[System.String]]>(System.Threading.Tasks.Task`1[System.String] $input)
{
.Block(
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter $awaiter,
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[System.String] $awaiter,
System.Int32 $state,
System.Int32 $resumeState,
System.Threading.Tasks.TaskCompletionSource`1[System.String] $taskCompletionSource,
System.Action $continuation,
System.Exception $exception) {
$taskCompletionSource = .New System.Threading.Tasks.TaskCompletionSource`1[System.String](.Constant<System.Threading.Tasks.TaskCreationOptions>(RunContinuationsAsynchronously));
$continuation = .Lambda #Lambda2<System.Action>;
.Invoke $continuation();
$taskCompletionSource.Task
}
}
.Lambda #Lambda2<System.Action>() {
.Try {
.Loop {
.Switch ($state) {
.Case (0):
.Block() {
$state = 1;
.If (
!($awaiter = .Call (.Call (.Call System.Threading.Tasks.Task.Delay(50)).ConfigureAwait(False)).GetAwaiter()).IsCompleted
) {
.Block() {
.Call $awaiter.OnCompleted($continuation);
.Break :break { }
}
} .Else {
.Default(System.Void)
}
}
.Case (1):
.Block() {
$state = 2;
.Call $awaiter.GetResult();
.If (
!($awaiter = .Call (.Call $input.ConfigureAwait(False)).GetAwaiter()).IsCompleted
) {
.Block() {
.Call $awaiter.OnCompleted($continuation);
.Break :break { }
}
} .Else {
.Default(System.Void)
}
}
.Case (2):
.Block(System.String $result:2) {
$result:2 = .Call $awaiter.GetResult();
.Call $taskCompletionSource.SetResult($result:2);
.Break :break { }
}
.Default:
.Throw .New System.InvalidOperationException()
}
}
.LabelTarget :break:
} .Catch (System.Exception $ex) {
.Call $taskCompletionSource.SetException($ex)
}
}
This is a simple example; but the async conversion can not only handle await, but also the control flow expressions (loop, conditional, label/goto, try..catch..finally) in order to offer support for a wide variety of Expression Trees.

Related

How to inline a Call?

How can I retrieve the body of a defined method and convert it directly to a LINQ Expression?
For example this method is defined (in Program.cs):
public static void InlineMethod(string message)
{
Console.WriteLine(message);
Debug.WriteLine(message);
}
And the following represents the LINQ Expression:
var method = typeof(Program).GetMethod(nameof(InlineMethod))!;
var param = Expression.Parameter(typeof(string));
var call = Expression.Call(method, param);
var block = Expression.Block(call);
var lambda = Expression.Lambda(block, param);
((Action<string>)lambda.Compile())("Hello World");
This works of course because the called method is compiled as a call:
.Block() {
.Call Solution.Program.InlineMethod($var1)
}
The goal is to dynamically (even if the method body changes) retrieve the body of the InlineMethod and produce (in this example) the following compile results:
.Block() {
.Call System.Console.WriteLine($var1);
.Call System.Diagnostics.Debug.WriteLine($var1);
}

Does the LINQ Expression API offer no way to create a variable?

I want to validate my assumption that the LINQ Expression API does not have any means for us to create an expression that represents the creation of a local variable.
In other words, you cannot create an expression to represent:
int local;
since that is a variable declaration statement, and the API does not support statement lambdas. The only state that a lambda expression, as represented by the LINQ Expression API (and not a delegate instance) can work with is parameters it receives and the captured variables it receives via a closure.
Is my assumption (based on a few months of practice of the LINQ Expression API) correct?
False. There are some overloads of Expression.Block to do it.
What is true is that you can't create a lambda expression through the use of the C# compiler that has a variable, but that is a limitation of the compiler.
So you can't
Expression<Func<int>> exp = () => {
int v = 1;
return v;
};
but you can
var variable = Expression.Variable(typeof(int));
var lambda = Expression.Lambda<Func<int>>(
Expression.Block(
new[] { variable },
Expression.Assign(variable, Expression.Constant(1)),
variable)); // With lambda expressions, there is an implicit
// return of the last value "loaded" on the stack
since that is a variable declaration statement, and the API does not support statement lambdas.
This was true in .NET < 4.0 . In .NET 4.0 Microsoft added Expression methods to build nearly everything that can be present in the body of a method (there are some missing "things", like unsafe code keywords/operators, plus there are the primitives but there aren't complex constructs like the for or lock, that can be built on top of other constructs). Note that 90% of those added things are incompatible with LINQ-to-SQL/EF.
Well, you can use Expression.Block to declare a block which contains local variables...
For example:
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
var x = Expression.Variable(typeof(int), "x");
var assignment1 = Expression.Assign(x, Expression.Constant(1, typeof(int)));
var assignment2 = Expression.Assign(x, Expression.Constant(2, typeof(int)));
var block = Expression.Block(new[] { x }, new[] { assignment1, assignment2 });
}
}
That builds an expression tree equivalent to:
{
int x;
x = 1;
x = 2;
}
The C# compiler doesn't use this functionality within lambda expression conversions to expression trees, which are currently still restricted to expression lambdas, as far as I'm aware.

Utilizing Funcs within expressions?

Background
I have an example of a test that passes but an error that happens down the pipeline and I'm not sure why. I'd like to figure out what's going on but I'm new to Expression construction and don't want to make any assumptions.
This is for a search filtering mechanism. It uses ServiceStack's PredicateBuilder implementation. I essentially have a list of values that I pass in, and I want it to construct an expression tree. I had previously done this just with Func<T<bool>> but realized that I needed to wind up with Expression<Func<T<bool>>>. Bummer.
The Goal
Search filters built from Re-usable search filter types, which built out of Funcs and Expressions that allows me to pass in a field name from an object along with values I should match on and wind up with something that we can run a Where() statement against.
The Code / Issue
The generic "nullable bool" filter I'm trying -- sets up the acceptable items and returns a func that is meant to help filter:
public class NullableBoolFilter : IGenericSearchFilter<bool?>
{
public Func<bool?, bool> GetFilterFunc(string valuesToProcess)
{
var acceptableValues = new List<bool?>();
if (string.IsNullOrWhiteSpace(valuesToProcess))
{
// all values acceptable
acceptableValues = new List<bool?>{true, false, null};
}
else
{
if (!valuesToProcess.Contains("0") && !valuesToProcess.Contains("1"))
{
throw new ArgumentException("Invalid Nullable boolean filter attribute specified");
}
if (valuesToProcess.Contains("0"))
{
acceptableValues.Add(false);
}
if (valuesToProcess.Contains("1"))
{
acceptableValues.Add(true);
}
}
Func<bool?, bool> returnFunc = delegate(bool? item) { return acceptableValues.Any(x=>x == item); };
return returnFunc;
}
}
Then I have another filter, which inherits from the NullableBoolFilter and attempts to use the Func:
public class ClaimsReportIsMDLFilter : NullableBoolFilter, ISearchFilter<vSEARCH_ClaimsReport>
{
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(string valuesToProcess)
{
var theFunc = base.GetFilterFunc(valuesToProcess);
Expression<Func<vSEARCH_ClaimsReport, bool>> mdlMatches = item => theFunc(item.IsMDL);
var predicate = PredicateBuilder.False<vSEARCH_ClaimsReport>();
predicate = predicate.Or(mdlMatches);
return predicate;
}
}
The following test passes:
public class ClaimsReportIsMDLFilterTests
{
// ReSharper disable InconsistentNaming
private readonly vSEARCH_ClaimsReport ItemWithMDL = new vSEARCH_ClaimsReport { IsMDL = true };
private readonly vSEARCH_ClaimsReport ItemWithoutMDL = new vSEARCH_ClaimsReport { IsMDL = false };
private readonly vSEARCH_ClaimsReport ItemWithNullMDL = new vSEARCH_ClaimsReport { IsMDL = null };
// ReSharper restore InconsistentNaming
[Fact]
public void WithSearchValueOf1_HidesNonMDLAndNull()
{
var sut = this.GetCompiledExpressionForValues("1");
sut.Invoke(ItemWithMDL).Should().BeTrue();
sut.Invoke(ItemWithoutMDL).Should().BeFalse();
sut.Invoke(ItemWithNullMDL).Should().BeFalse();
}
private Func<vSEARCH_ClaimsReport, bool> GetCompiledExpressionForValues(string searchValue)
{
return new ClaimsReportIsMDLFilter().GetExpression(searchValue).Compile();
}
}
The Problem
When I actually attempt to run this, I receive the error:
variable 'param' of type 'vSEARCH_ClaimsReport' referenced from scope '', but it is not defined
It makes sense to me why this might occur -- at the time it's evaluated, I don't have a real object to pass into the Func. However, I'm confused as to why my tests might pass but this doesn't in actual usage.
Questions
Why might my tests pass but I still receive this error?
How the heck should I begin trying to fix this?
Is there a remotely easy way to take that Func and turn it into an Expression that I can pass a field into?
Do I need to abandon the generic filter idea and have each class manually add expressions to the PredicateBuilder based on input passed in? That's doable, but it seems like the work could be reduced more.
Why might my tests pass [...]
Because your test is simply compiling the expression down into the code that it represents and invoking it. It doesn't need to actually parse the expression tree and look at what the code it represents is doing, it just runs it and ensures that the output is right.
Why might [...] I still receive this error?
Because when you're actually using it, it's not just executing the code; rather it is looking through the expression tree to try to determine what the code is doing so that it can be translated into something else, not so that it can be run as C# code.
Your expression is doing nothing but calling a delegate. There is no way for someone traversing the expression tree to see inside the delegate and know what it's doing. Knowing that you're calling another method isn't something that can be translated into another language.
How the heck should I begin trying to fix this?
You need to generate an Expression from the start, rather than generating a Func and then just creating an Expression that calls it.
Is there a remotely easy way to take that Func and turn it into an Expression that I can pass a field into?
No. You'd need to pull out the IL code of the function, decompile that into C# code, then build up Expression objects to represent that code. That's pretty much just not going to happen.
You're pretty much going to need to have GetFilterFunc return an Expression, to get this to work. Fortunately, this is quite easy to do, given what you have. You simply need to change the method signature and to replace the last two lines with the following:
return item => acceptableValues.Any(x => x == item);
And voila. The lambda can be compiled into an Expression object, rather than a delegate, based on context, so if the return type of the method is an Expression<Func<bool?,bool>> that's what you'll get.
Now, to use this in GetExpression. First off, the PredicateBuilder isn't really doing anything. Adding an OR FALSE to your expression changes nothing meaningful about it. All of that can go. All that leaves us with is using an Expression<Func<bool?,bool>> and changing it into an Expression<Func<vSEARCH_ClaimsReport, bool>> by pulling out a boolean property. To do this is a bit more work for expressions than for delegates. Rather than just invoking the expression, we need to do a tad more work to compose them. We'll want to write a method to do this operation:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
And this relies on the use of the following method to replace all instances of one expression with another:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
What this is doing is replacing all instances of the second expression's parameter with the body of the first expression, effectively inlining that expression into the second. The rest is simply replacing all of the parameters with a new single parameter and wrapping it back up into a lambda.
Now that we have that, our method is quite easy:
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(
string valuesToProcess)
{
Expression<Func<vSEARCH_ClaimsReport, bool?>> selector =
item => item.IsMDL;
return selector.Compose(base.GetFilterFunc(valuesToProcess));
}

Switch statement with non-constant-expression - Extends C#/IDE ability

Before you start criticizing and pointing me §8.7.2 of C# specification, read carefully :)
We all know how switch looks like in C#. Ok so consider the class MainWindow with "nasty" Bar method
static int barCounter = 0;
public static int Bar()
{
return ++barCounter;
}
Somewhere in this class we have code like this
Action switchCode = () =>
{
switch (Bar())
{
case 1:
Console.WriteLine("First");
break;
case 2:
Console.WriteLine("Second");
break;
}
};
switchCode();
switchCode();
In the console window we will see
First
Second
Using Expressions in C# we could do the same – writing much same code
var switchValue = Expression.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var #switch = Expression.Switch(switchValue,
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("First")),
Expression.Constant(1)
),
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("Second")),
Expression.Constant(2)
)
);
Action switchCode = Expression.Lambda<Action>(#switch).Compile();
switchCode();
switchCode();
In DebugView we could see "code behind" this expression
.Switch (.Call WpfApplication1.MainWindow.Bar()) {
.Case (1):
.Call System.Console.WriteLine("First")
.Case (2):
.Call System.Console.WriteLine("Second")
}
Ehmm, what if we use Expression.Call instead Expression.Constant?
public static bool foo1() { return false; }
public static bool foo2() { return true; }
// .....
var foo1 = Ex.Call(typeof(MainWindow).GetMethod("foo1"));
var foo2 = Ex.Call(typeof(MainWindow).GetMethod("foo2"));
var switchValue = Ex.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var #switch = Ex.Switch(Ex.Constant(true),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("First")),
foo1
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("OK!")),
Ex.Equal(switchValue, Ex.Constant(2))
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("Second")),
foo2
)
);
Action switchCode = Ex.Lambda<Action>(#switch).Compile();
switchCode();
switchCode();
Console window shows, as we expected
Second
OK!
And DebugView
.Switch (True) {
.Case (.Call WpfApplication1.MainWindow.foo1()):
.Call System.Console.WriteLine("First")
.Case (.Call WpfApplication1.MainWindow.Bar() == 2):
.Call System.Console.WriteLine("OK!")
.Case (.Call WpfApplication1.MainWindow.foo2()):
.Call System.Console.WriteLine("Second")
}
So it is possible to use non-constant expression in case-statement :)
Ok, I known this is little ‘messy’ code. But here comes my question (finally :P):
Is there any way to extends functionality of IDE/VisualStudio/compiler to do this, but with more elegant code?
Something like this
switch (true)
{
case foo1():
Console.WriteLine("First");
break;
case Bar() == 2:
Console.WriteLine("OK!");
break;
case foo2():
Console.WriteLine("Second");
break;
}
I know this will be some extension and code will be not the same (not the same performance). But I wonder if this is even possible to "change" code on-the-fly – like anonymous function or yield return is transform to nested class.
I hope someone goes through the above text and leave some clue.
In general, there are no extension points in the Microsoft C# compiler as far as I know (and even Roslyn isn't planning to change that). But nothing is stopping you from writing your own C# compiler, or, more realistically, modifying the open source Mono C# compiler.
In any case, I think it's much more trouble than what it's worth.
But maybe you can do what you want using something that's already in the language, namely, lambdas and method calls, to form a “fluent switch”:
Switch.Value(true)
.Case(() => Foo(), () => Console.WriteLine("foo"))
.Case(() => Bar() == 2, () => Console.WriteLine("bar == 2"));
If you don't mind that all the condition values will be evaluated every time, you simplify that a bit:
Switch.Value(true)
.Case(Foo(), () => Console.WriteLine("foo"))
.Case(Bar() == 2, () => Console.WriteLine("bar == 2"));
No, it's not possible, nor that I'm aware of. It's already kind of miracle that you can use a string inside switch statement (reference type with immutable behavior). For these kind of cases just use if, if/else, if/elseif combinations.
There aren't currently extensions that do that sort of thing. Although it's worth pointing out that MS SQL allows for exactly what you are looking for
SELECT
Column1, Column2,
CASE
WHEN SomeCondition THEN Column3
WHEN SomeOtherCondition THEN Column4
END AS CustomColumn
FROM ...
The problem with this becomes understanding precedence; what happens when both conditions are true? In SQL the case statement returns the value from the first statement that is true, and ignores other cases, but that behavior might not be what you wanted.
The strength of C# is that it's impossible to code switches in such a way that both case 1 and case 2 can be true at the same time, so you are guaranteed only one correct answer.
As we all know "Switches" exposes a similar functionality to an if. Most of us (myself include) see it as a syntax sugar -- it's easier to read a bunch of cases on a certain switch then read through a number of if/else if/.../else. But the fact is that switch is no syntax sugar.
What you must realize is that the code generated for switch (be it IL or machine code) is not the same as the code generated for sequential ifs. Switch has a nice optimization which, as #Ed S. already pointed out, enables it to run in a constant time.

Moq and reflection, passing dynamically generated expression tree / lambda to moq

Is it possible to write code like the following. I'm trying to using Moq with objects that I'm reflecting on as part of a testing framework. The code below raises a "Unhandled expression type: 'Goto'" exception from Moq, which I guess is expecting something different. It kind of looks like it should work though!
private void button1_Click(object sender, EventArgs e)
{
Ifoo = foo Foo();
// Create input parameter for lambda
ParameterExpression value = Expression.Parameter(typeof(IFoo), "value");
// create return statement for lambda
Expression setupProperty = Expression.Return(Expression.Label(), Expression.Property(value, "Bar"), typeof(string));
// convert expression to lambda (should now be the equivalent of "v => v.Bar")
var func = Expression.Lambda<Func<IFoo, string>>(setupProperty, value);//.Compile();
//string s = func(foo); // this bit works fine if .Compile() is included
var mockFoo = new Mock<IFoo>();
mockFoo.SetupProperty(func); // exception thrown by moq here, obviously isn't exactly the same as "v => v.Bar"
mockFoo.Object.Bar = "Burge+";
}
Thanks!
Ok, this is possible, here is the corrected code.
// Create input parameter for lambda
ParameterExpression value = Expression.Parameter(typeof(IFoo), "value");
// create return statement for lambda
Expression setupProperty = Expression.Property(value, "Bar");
// convert expression to lambda (should now be the equivalent of "v => v.Bar")
var func = Expression.Lambda<Func<IFoo, string>>(setupProperty, value);
var mockFoo = new Mock<IFoo>();
mockFoo.SetupProperty(func); // this works now
mockFoo.Object.Bar = "Burge+";
I investigated this by creating an expression from a lambda using the code below
Expression<Func<IFoo, string>> setupBar = v => c.Bar;
I then looked at this in the debugger in vs 2010. Expressions have a "Debug View" that shows a text representation of the expression so it is possible to add a watch on that or something similar. The above comes out as
.Lambda #Lambda1<System.Func`2[WindowsFormsApplication1.IFoo,System.String]>(WindowsFormsApplication1.IFoo
$v) {
$v.Bar
}
I looked at this and tried to work out what Expressions would make this, then created an expression and compared it in the debugger.
The interesting thing for me is that although this expression returns a value there is no assignment or return statement. I guess this must be implicit somehow.

Categories