I have a call to a remote service which is described as following:
var user = new User { Name = "check" };
WcfService<IMyService>.Call(s => s.MyMethod(1, "param", user, new Entity { ID = 2 }));
In my Call
method, I need to serialize this method call to JSON, which will be put in the WebSphere queue:
{
"Interface": "IMyService",
"Method": "MyMethod",
"Arguments": [
1,
"param",
{
"Name": "check"
},
{
"ID": 2
}
]
}
I know how to obtain interface and method names, but I cannot obtain non-constant values:
public static class WcfService<TInterface>
{
public static void Call(Expression<Action<TInterface>> expr)
{
var mce = (MethodCallExpression)expr.Body;
string interfaceName = typeof(TInterface).Name;
string methodName = mce.Method.Name;
var args = mce.Arguments
.Cast<ConstantExpression>()
.Select(e => e.Value)
.ToArray();
}
}
This code works for 1
and "param"
, but does not work for user
and new Entity { ID = 2 })
since they are FieldExpression
and NewExpression
respectively. How to get the actual values, passed to a function call, instead of their expression representation?
Update: The answer from the suggested duplicate question is not suitable, because I don't want to compile my expression and execute it - I only need to evaluate arguments.
I have combined the information from this answer and Pieter Witvoet's answer and received the following function:
public static object Evaluate(Expression expr)
{
switch (expr.NodeType)
{
case ExpressionType.Constant:
return ((ConstantExpression)expr).Value;
case ExpressionType.MemberAccess:
var me = (MemberExpression)expr;
object target = Evaluate(me.Expression);
switch (me.Member.MemberType)
{
case MemberTypes.Field:
return ((FieldInfo)me.Member).GetValue(target);
case MemberTypes.Property:
return ((PropertyInfo)me.Member).GetValue(target, null);
default:
throw new NotSupportedException(me.Member.MemberType.ToString());
}
case ExpressionType.New:
return ((NewExpression)expr).Constructor
.Invoke(((NewExpression)expr).Arguments.Select(Evaluate).ToArray());
default:
throw new NotSupportedException(expr.NodeType.ToString());
}
}
Now, I can simply do the following:
var args = mce.Arguments.Select(ExpressionEvaluator.Evaluate).ToArray();