Accessing calling object from MethodCallExpression - c#

I'm trying to learn about Expression trees, and I've created a method that takes an
Expression<Func<bool>>
and executes it if it satisfies some conditions - see the code below.
private static void TryCommand(Expression<Func<bool>> expression)
{
var methodCallExpression = expression.Body as MethodCallExpression;
if (methodCallExpression == null)
{
throw new ArgumentException("expression must be a MethodCallExpression.");
}
if (methodCallExpression.Object.Type != typeof (MyClass))
{
throw new ArgumentException("expression must be operating on an instanceof MyClass.");
}
var func = expression.Compile();
var success = func.Invoke();
if(!success)
{
Console.WriteLine(methodCallExpression.Method.Name + "() failed with error code " + (func.Target as MyClass).GetError());
}
}
The problem that
(func.Target as MyClass)
is null. Clearly I'm doing something wrong! How do I access the instance that the method is operating on?

Akash, once you have a MethodCallExpression it's simple to recover the method caller.
You must recover the MemberExpression and build an Expression tree that evaluates it.
See the code below:
MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
MemberExpression memberExpression = (MemberExpression)methodCallExpression.Object;
Expression<Func<Object>> getCallerExpression = Expression<Func<Object>>.Lambda<Func<Object>>(memberExpression);
Func<Object> getCaller = getCallerExpression.Compile();
MyClass caller = (MyClass)getCaller();
Hope this helps,
Ricardo Lacerda Castelo Branco

The target of the method call is an instance of MyClass, but the delegate itself isn't the method call. It's something which will perform the method call when it's executed.
If you look at func.Target, you'll see it's a System.Runtime.CompilerServices.ExecutionScope.
Now you could test for that, cast to it, and then fetch either the Locals or the Globals (not sure which) to get the target. However, I suspect it would be cleaner just to change to use a Func<int> (or whatever type your error code is) and return the error code when you execute the delegate in the first place. Then you wouldn't even need an expression tree.
EDIT: Given your comments, I'd suggest:
public static void TryCommand(Expression<Func<MyClass,bool>> command,
MyClass c)
{
// Code as before to find the method name etc.
Func<MyClass, bool> compiled = command.Compile();
if (!compiled(c))
{
Console.WriteLine(methodCallExpression.Method.Name
+ "() failed with error code " + c.GetError());
}
}
You'd then call it with:
TryCommand(x => x.SomeMethod(), myClass);

The target is null because the method is static. In reflection Invoke(..) on a static MethodInfo will ignore the target. This is likely an extension method, in which case the first argument is the inferred target.
Since most of LINQ is based on extension methods you'll see this quite often going forward with reflection.

Related

Why is the ?? operator not working in Moq setup method

Could someone explain to me, why this doesn't work?
builder.Setup(b => b.BuildCommand(query ?? It.IsAny<string>())).Returns(command);
If query is null, BuildCommand will be passed null, and not It.IsAny<string>()
Instead, I have to do this:
if(query == null)
builder.Setup(b => b.BuildCommand(It.IsAny<string>())).Returns(command);
else
builder.Setup(b => b.BuildCommand(query)).Returns(command);
Is it related to the delegate?
EDIT - Complete example
public static void ReturnFromBuildCommand(this Mock<IQueryCommandBuilder> builder, IQueryCommand command, string query = null)
{
if(query == null)
builder.Setup(b => b.BuildCommand(It.IsAny<string>())).Returns(command);
else
builder.Setup(b => b.BuildCommand(query)).Returns(command);
}
Then I can call it like
var command = new Mock<IQueryCommand>();
var builder = new Mock<IQueryCommandBuilder>();
builder.ReturnFromBuildCommand(command.Object);
Or
string query = "SELECT Name FROM Persons;";
builder.ReturnFromBuildCommand(command.Object, query);
Depending on whether I care about the parameter or not.
The Setup method of the mock takes in an expression, which the Moq framework then deconstructs to determine the method being called and the arguments to it. It then sets up an interceptor to match the arguments.
You can see this in the Mock source:
internal static MethodCallReturn<T, TResult> Setup<T, TResult>(
Mock<T> mock,
Expression<Func<T, TResult>> expression,
Condition condition)
where T : class
{
return PexProtector.Invoke(() =>
{
if (expression.IsProperty())
{
return SetupGet(mock, expression, condition);
}
var methodCall = expression.GetCallInfo(mock);
var method = methodCall.Method;
var args = methodCall.Arguments.ToArray();
ThrowIfNotMember(expression, method);
ThrowIfCantOverride(expression, method);
var call = new MethodCallReturn<T, TResult>(mock, condition, expression, method, args);
var targetInterceptor = GetInterceptor(methodCall.Object, mock);
targetInterceptor.AddCall(call, SetupKind.Other);
return call;
});
}
Here args is of type Expression[].
(reference: https://github.com/moq/moq4/blob/master/Source/Mock.cs#L463)
This args array is passed into the constructor for the Moq type MethodCallReturn as the parameter arguments. That constructor (via the base class MethodCall) generates an argument matcher using MatcherFactory.Create. (reference: https://github.com/moq/moq4/blob/master/Source/MethodCall.cs#L148)
This is where things start to get interesting!
In the MatcherFactory.Create method, it tries to determine the type of the argument's Expression by looking that the Expression.NodeType and/or checking it against known types, such as MatchExpression (which is what something like Is.Any<string>() would be).
(reference: https://github.com/moq/moq4/blob/master/Source/MatcherFactory.cs#L54)
So let's take a step back. In your specific case, the code query ?? Is.Any<string>() is compiled down to an expression itself -- something like this ugly mess (as generated by the dotPeek decompiler):
(Expression) Expression.Coalesce((Expression) Expression.Field((Expression) Expression.Constant((object) cDisplayClass00, typeof (Extension.\u003C\u003Ec__DisplayClass0_0)),
FieldInfo.GetFieldFromHandle(__fieldref (Extension.\u003C\u003Ec__DisplayClass0_0.query))),
(Expression) Expression.Call((Expression) null, (MethodInfo) MethodBase.GetMethodFromHandle(__methodref (It.IsAny)), new Expression[0]))
And that's what the first argument looks like. You can rewrite your code to better express what Moq sees, like this:
public static void ReturnFromBuildCommand(this Mock<IQueryCommandBuilder> builder, IQueryCommand command, string query = null)
{
Expression<Func<IQueryCommandBuilder, IQueryCommand>> expressOfFunc = commandBuilder => (commandBuilder.BuildCommand(query ?? It.IsAny<string>()));
var methodCall = expressOfFunc.Body as MethodCallExpression;
var args = methodCall.Arguments.ToArray();
var nodeType = args[0].NodeType;
builder.Setup(expressOfFunc)
.Returns(command);
}
If you place a breakpoint, you can see that the value of nodeType is Coalesce. Now, go back and change it to just use query, and nodeType becomes MemberAccess. Use It.IsAny<string>(), and nodeType is Call.
This explains the differences between the three approaches and why it's not acting like you expected. As for why it triggers on null is not clear to me, to be honest, but whatever matcher comes out of MatcherFactory.CreateMatcher seems to think null is a valid value for your mock configuration.

Getting method name from Expression

Given the following method signature:
string GetActionName<TController, T1, TResult>(Expression<Func<TController, Func<T1, TResult>>> expression)
How can I get the method name from the following implementation:
GetActionName<EventsController, int, IEnumerable<EventDto>>(c => c.GetEventsByIdLocation);
Where GetEventsById has the signature of:
IEnumerable<EventDto> GetEventsByIdLocation(int id)
My current attempt is giving me the exception:
Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'.
var convertExpression = (UnaryExpression)expression.Body;
var memberExpression = (MemberExpression)convertExpression.Operand;
return memberExpression.Member.Name;
The main problem is that in your call, you are not actually calling the method, but returning it. This caused the expression tree to contain a call to a method called CreateDelegate.
Once we have that in our methodCallExpression we need to extract the object, and read its value, which is your method.
Disclaimer: This worked for me with a scenario that I think was equal to yours. If it, however, is the best way to solve the larger problem I do not know. It seems to be fairly slow.
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var constantExpression = (ContantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)constantExpression.Value;
return methodInfo.Name
Another option would be to provide an actual method call to the method, like so:
GetActionName<EventsController, IEnumerable<EventDto>>(
c => c.GetEventsByIdLocation(0));
Which would require you to change the method to:
string GetActionName<TController, TResult>(
Expression<Func<TController, TResult>> expression)
{
return ((MethodCallExpression)expression.Body).Method.Name;
}
This solution will probably perform a lot faster. Allthough I havn't done any benchmarks or anything. Also, this option does not tie you to only being able to get the names of methods that take one int parameter.

How to set parameter of method using reflection

The following code is a helper I've created for a system which allows administrators to create their own queries on a database. It returns a lambda expression based on the method and value provided.
I am attempting to find a way to pass parameters to the method call - in this example I am using the StartsWith parameter of String, and attempting to set StringComparison.OrdinalIgnoreCase as a parameter.
There will be others parameters required too, depending on the type of the property specified. I'm hoping that understanding the method of supplying the string comparison property will enable me to add the rest later.
The underlying code works correctly, I just need it to be case-insensitive.
I have used this question as a guide, but the solution does not seem applicable here.
Here is the code:
public static class LambdaExpressionHelper<T> {
public static Expression<Func<T, bool>> Build(string propertyName, string method, string propertyValue) {
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
ParameterExpression e = Expression.Parameter(typeof(T), "e");
MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
ConstantExpression c = Expression.Constant(propertyValue, m.Type);
MethodInfo mi = m.Type.GetMethod(method, new Type[] { m.Type }, );
// The below caused errors
//object classInstance = Activator.CreateInstance(typeof(T), null);
//object[] paramArray = new object[] { StringComparison.OrdinalIgnoreCase };
//mi.Invoke(classInstance, paramArray);
Expression call = Expression.Call(m, mi, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
return lambda;
}
}
// External code:
var lambda = LambdaExpressionHelper<MailingListMember>.Build("EmailAddress", "StartsWith", "RoRy#");
Thanks for any help.
In the general case this should work:
public static Expression<Func<T, bool>>
Build(string propertyName, string method, params object[] args)
{
var propertyInfo = typeof(T).GetProperty(propertyName);
var e = Expression.Parameter(typeof(T), "e");
var m = Expression.MakeMemberAccess(e, propertyInfo);
var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
var c = args.Select(a => Expression.Constant(a, a.GetType())).ToArray();
Expression call = Expression.Call(m, mi, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
return lambda;
}
The idea is that you accept any number of constant arguments, and use their types to select the appropriate overload when calling GetMethod. After that, you create the appropriate number of constant expressions from those arguments to pass to Expression.Call.
So with the above code, you could do:
var l1 = LambdaExpressionHelper<MailingListMember>.Build(
"EmailAddress", "StartsWith", "RoRy#");
var l2 = LambdaExpressionHelper<MailingListMember>.Build(
"EmailAddress", "StartsWith", "RoRy#", StringComparison.OrdinalIgnoreCase);
If you also need to get the value StringComparison.OrdinalIgnoreCase from the string "StringComparison.OrdinalIgnoreCase", I would factor this out into a separate method so that the interface of Build can remain generic. Exactly how to do it is covered in Getting Enum value via reflection (and I guess in lots of similar questions as well).
Note: I don't have convenient access to a compiler right now, so please excuse any mistakes.
I'm not sure i understand your question exactly, but hopefully this will help you on the way.
If you are using .NET 4.0 you can use the new keyword "dynamic" for much easier reflection code:
dynamic myDynamicObj = "Hello World!"; // or Activator.CreateInstance...
var doesIndeed = myDynamicObj.StartsWith("Hello", StringComparison.OrdinalIgnoreCase);
This does evaluate at run time so make sure spelling/case etc is correct.
Edit:
Assuming you always wanted to call methods with one String-arg returning bool, a possible solution would be to create a delegate type -
delegate bool CompareString(String str);
and than have the second argument of Build as that type:
Build(String .., CompareString cs, String ...)
But this does not work if you need to add extra arguments, as in the second arg of type StringComparison. A if/switch could be the answer there though, i.e if(CompareString is StartsWith)...
Sorry, not at a windows-computer so i can't test further.

Dynamically get the result of a Func<T,bool> invocation

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);

What's the best way to define & access selected properties in C#?

From my recent question, I try to centralize the domain model by including some silly logic in domain interface. However, I found some problem that need to include or exclude some properties from validating.
Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.
public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>
(
u => u.ID,
u => u.LogOnName,
u => u.HashedPassword
);
Thanks,
Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).
Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.
I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.
Another thought; if you are using Expression, you could do something like:
public void IncludeProperties<T>(
Expression<Func<T,object>> selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:
public static void IncludeProperties<T>(
Expression<Func<T, object>> selectedProperties)
{
NewExpression ne = selectedProperties.Body as NewExpression;
if (ne == null) throw new InvalidOperationException(
"Object constructor expected");
foreach (Expression arg in ne.Arguments)
{
MemberExpression me = arg as MemberExpression;
if (me == null || me.Expression != selectedProperties.Parameters[0])
throw new InvalidOperationException(
"Object constructor argument should be a direct member");
Console.WriteLine("Accessing: " + me.Member.Name);
}
}
static void Main()
{
IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):
var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Here's the shortest expression I can come up with:
public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
// some logic to store parameter
}
public static void S(params object[] props)
{
// dummy method to get to the params syntax
}
[Test]
public void ParamsTest()
{
IncludeProperties(u => S(
u.Id,
u.Name
));
}

Categories