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.
Related
I'm using a combination of reflection and expression trees, and want to pass back certain property accessors from a class to a calling method. My current code has a method traversing the class and returning a list of MemberExpressions. The caller then iterates over the member expressions and creates lambdas, which should then be called with an instance of the inspected class to return the value of the property.
Here is a sample of what it would look like without the method calls (Runnable in LINQPad):
void Main()
{
var t = new Test { Prop = "Test" };
var property = t.GetType().GetProperty("Prop");
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
var func = lambda.Compile();
var result = func(t);
result.Dump();
}
class Test {
public string Prop { get; set; }
}
This does not work, throwing this exception:
InvalidOperationException: variable 'baseType' of type 'UserQuery+Test' referenced from scope '', but it is not defined
However, if I change the creation of the lambda to this:
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);
That is, replace the Expression.Parameter with the variable used earlier, then it works. This is not (easily) possible in the scenario where I want to use it, since I would have to return the original parameter along with the list (I could return a tuple, of course, but I would prefer not to, if it is not necessary).
Why does it work like this? Inspecting the DebugView of the lambda, they are exactly the same no matter what approach is used:
.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
$baseType.S
}
Yes, you need to refer ParameterExpression, used earlier. This won't compile too:
private String Foo(Test myParam)
{
return myAnotherParam.MyProperty;
}
With instatiating new ParameterExpression in lambda, you're doing the same thing (but note, when making lambda, you're doing it in reversed order - first, you're constructing a method body, then - a method declaration):
// return myAnotherParam.MyProperty;
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
// private String Foo(MyClass myParam)
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
For various reasons I'm constructing a C# lambda dynamically using the expression tree facilities. e.g. I can make a Func<string,bool> at runtime as shown in the following snippet.
public static bool myMethod( object obj ) { … }
// Construct a Func<string,bool>
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (string))};
var callMyMethod = Expression.Call(myMethod, lambdaParams);
var lambda = Expression.Lambda(typeof(Func<string,bool>), callMyMethod, lambdaParams);
var del = (Func<string,bool>)lambda.Compile();
del("foo"); // works
However if I use the same code to try to make a Func<int,bool> or a Func<DateTime,bool> it blows up where indicated with the following strange exception:
// Construct a Func<DateTime,bool> or perhaps a struct type fails... why?
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (DateTime))};
var callMyMethod = Expression.Call(myMethod, lambdaParams); // Blows up here…
System.ArgumentException: Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'Boolean myMethod(System.Object)'
So, string works and List<string> works but int32 does not work nor does DateTime. What is going on? I don't know how the deep internals of C# work but I am guessing it's due to int really being handled as a primitive and maybe DateTime (being a struct) as well...
Any help with this would be greatly appreciated.
thanks,
Pat
As I understand it, Expression.Call doesn't perform auto-boxing of value-type arguments. I'm unable to find any documentation to that effect, but it is mentioned on this forum page.
One workaround would be to explicitly do the boxing conversion in the expression with Expression.TypeAs.
Creates a UnaryExpression that
represents an explicit reference or
boxing conversion where null is
supplied if the conversion fails.
In your case, this should work:
var boxedParams = lambdaParams.Select(p => Expression.TypeAs(p, typeof(object)))
.ToArray();
var callMyMethod = Expression.Call(myMethod, boxedParams);
(You don't need the fancy lambdas if there's only one parameter)
Depending on the real usage, you may have to check if the boxing conversion is necessary depending on whether the type(s) in question is(are) value-type(s).
Check this out: you have to box the DateTime, since DateTime isnt' a reference type!
// Construct a Func<DateTime,bool>
var myMethod = typeof(Program).GetMethod("myMethod");
var param = Expression.Parameter(typeof(DateTime));
var boxy = Expression.TypeAs(param, typeof(object));
var callMyMethod = Expression.Call(myMethod, boxy);
var lambda = Expression.Lambda(typeof(Func<DateTime, bool>), callMyMethod, new ParameterExpression[] { param });
var del = (Func<DateTime,bool>)lambda.Compile();
del(DateTime.Now); // works
I had a part of code that takes in lambda expressions at runtime, which I can then compile and invoke.
Something thing;
Expression<Action<Something>> expression = (c => c.DoWork());
Delegate del = expression.Compile();
del.DynamicInvoke(thing);
In order to save execution time, I stored those compiled delegates in a cache, a Dictionary<String, Delegate> which the key is the lambda expression string.
cache.Add("(Something)c => c.DoWork()", del);
For exact same calls, it worked fine. However I realized that I could receive equivalent lambdas, such as "d => d.DoWork()", which I should actually use the same delegate for, and I wasn't.
This got me wondering if there was a clean way (read "not using String.Replace", I already did that as a temporary fix) to replace the elements in a lambda expression, like maybe replacing them by arg0 so that both
(c => c.DoWork()) and (d => d.DoWork())
are transformed and compared as (arg0 => arg0.DoWork()) by using something fuctionnally similar to injecting a Expression.Parameter(Type, Name) in a lambda.
Is that possible ? (Answers can include C#4.0)
I used strings, since it was the easisest way for me. You can't manually change the name of the parameter expression (it has the "Name" property, but it is read-only), so you must construct a new expression from pieces. What I did is created a "nameless" parameter (actually, it gets an autogenerated name in this case, which is "Param_0") and then created a new expression almost the same as the old one, but using the new parameter.
public static void Main()
{
String thing = "test";
Expression<Action<String>> expression = c => c.ToUpper();
Delegate del = expression.Compile();
del.DynamicInvoke(thing);
Dictionary<String, Delegate> cache = new Dictionary<String, Delegate>();
cache.Add(GenerateKey(expression), del);
Expression<Action<String>> expression1 = d => d.ToUpper();
var test = cache.ContainsKey(GenerateKey(expression1));
Console.WriteLine(test);
}
public static string GenerateKey(Expression<Action<String>> expr)
{
ParameterExpression newParam = Expression.Parameter(expr.Parameters[0].Type);
Expression newExprBody = Expression.Call(newParam, ((MethodCallExpression)expr.Body).Method);
Expression<Action<String>> newExpr = Expression.Lambda<Action<String>>(newExprBody, newParam);
return newExpr.ToString();
}
There's more to a lambda expression than just the text. Lambdas are re-written by the compiler into something much more complicated. For example, they may close over variables (which could include other delegates). This means that two lambdas could look exactly the same, but perform completely different actions.
So you might have luck caching your compiled expression, but you need to give them a more meaningful name for the key than just the text of the expression. Otherwise no amount of argument substitution will help you.
I am trying to serialize something based upon meeting particular criteria.
To this end my original hope was to use attributes containing a lambda expression on an object's properties.
However, as this cannot be done I've settled for having a Func<T,bool> member within the class and passing the type (or first parameter type) and name of this Func through the property attribute. E.g.:
Func<SomeObject, bool> func = (p => p.Value == 4);
[FuncAtt(typeof(SomeObject), "func")]
public SomeObject PropertyName { get; set;}
In my serializer I need to call this Func<T, bool>.
Let's assume I have a Type t which is equal to typeof(SomeObject) in this case, or more abstractly, typeof(T). I can also get the Func<T,bool> itself, but only through reflection as an object.
My naive approach is something along these lines:
object func = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
Type funcType = typeof(Func<,>).MakeGenericType(attribute.Type, typeof(bool));
ParameterExpression p = Expression.Parameter(attribute.Type, objectToSerialize);
LambdaExpression l = Expression.Lambda(funcType, func, p); /* Won't work */
But this leads to the problem of casting a lambda to a delegate which is apparently erroneous.
I tried this in place of 'func':
(Expression)((Action)(() => func))
But that relies on func being a method call not a lambda.
So, can anyone point me in the right direction?
You can just do something like this, without need for expressions:
public static class Test
{
public static Predicate<int> func = s => s > 20;
}
and to get the value:
private void Form1_Load(object sender, EventArgs e)
{
var a = typeof(Test).GetField("func");
bool validates = ((Predicate<int>)a.GetValue(null)).Invoke(100);
}
edit to get the value without knowing the type:
bool validates = (bool)((Delegate)a.GetValue(null)).DynamicInvoke(100);
I think you can use Compile method of a lambda expression to cast it to a delegate.
here's what I found on MSDN:
The Expression<(Of <(TDelegate>)>)
type provides the Compile method,
that compiles the code represented by
the expression tree into an executable
delegate. This executable code is
equivalent to the executable code that
would have been generated had the
lambda expression been assigned to a
delegate type originally.
Here you can find it.
Not sure this is working sample, but this is the way:
// not sure what are you doing in this line, but assume it should return
// a method name specified in the attribute, e.g. "func" in your example.
// Also "func" must be a method (static one in my example) of SomeObject class
String funcname = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
ParameterExpression param = Expression.Parameter(typeof(SomeObject), "p");
MethodCallExpression call = Expression.Call(SomeObject, funcname, new Type[] { typeof(SomeObject), typeof(Boolean) }, param);
LambdaExpression lambda = Expression.Lambda<Func<SomeObject, Boolean>>(call, param);
now you can call the "func" method like this:
Boolean result = lambda.Compile()(SomeObjectInstance);
If I want to get a user input from Console to my Expression Tree. What is the best way to do it? and how to make variable 'name' duck typing?
Here are my code.
using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.Linq;
using Microsoft.Linq.Expressions;
namespace ExpressionTree
{
class Program
{
static void Main(string[] args)
{
List<Expression> statements = new List<Expression>();
// Output
MethodInfo Write = typeof(System.Console).GetMethod("Write", new Type[] { typeof(string) });
ConstantExpression param = Expression.Constant("What is your name? ", typeof(string));
Expression output = Expression.Call(null, Write, param);
statements.Add(output);
// Input
MethodInfo ReadLine = typeof(System.Console).GetMethod("ReadLine");
ParameterExpression exprName = Expression.Variable(typeof(String), "name");
Expression exprReadLine = Expression.Call(null, ReadLine);
// .NET 4.0 (DlR 0.9) from Microsoft.Scripting.Core.dll
// Expression.Assign and Expression.Scope
ScopeExpression input = Expression.Scope(Expression.Assign(exprName, exprReadLine), exprName);
statements.Add(input);
// Create the lambda
LambdaExpression lambda = Expression.Lambda(Expression.Block(statements));
// Compile and execute the lambda
lambda.Compile().DynamicInvoke();
Console.ReadLine();
}
}
}
Expression trees are designed to perform a fixed operation - in particular, the member-access is going to want a known MemberInfo (etc) at the point of expression tree creation (since they are immutable).
You could duplicate the generated code from dynamic if you are playing with 4.0, but to be honest, the better approach in this scenario is simply: don't use an expression tree.
Either reflection or ComponentModel (TypeDescriptor) would be ideal for this dynamic access to a member.
Also - calling Compile on something you use only once isn't saving any time, and using DynamicInvoke isn't either... you need to use the typed delegate form (Invoke).