我打电话给远程服务,其描述如下:
var user = new User { Name = "check" };
WcfService<IMyService>.Call(s => s.MyMethod(1, "param", user, new Entity { ID = 2 }));
在我的Call
方法中,我需要将此方法调用序列化为JSON,该方法将放入WebSphere队列中:
{
"Interface": "IMyService",
"Method": "MyMethod",
"Arguments": [
1,
"param",
{
"Name": "check"
},
{
"ID": 2
}
]
}
我知道如何获取接口和方法名称,但我无法获得非常量值:
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();
}
}
此代码适用于1
和"param"
,但不适用于user
和new Entity { ID = 2 })
,因为它们分别为FieldExpression
和NewExpression
。如何获取实际值,传递给函数调用,而不是表达式表示?
更新: suggested duplicate question的答案不合适,因为我不想编译我的表达式并执行它 - 我只需要评估参数。
答案 0 :(得分:1)
FieldExpression
有Member
(字段)和Expression
,在这种情况下是ConstantExpression
,其中包含包含该字段的对象。这里,常量表达式的Value
是一个捕获本地user
变量的匿名对象。将Member
投射到FieldInfo
允许您在其上调用GetValue
,并通过传递该常量表达式的Value
,您将获得User
个对象正在寻找。
NewExpression
具有Constructor
和Arguments
属性(表达式列表),但没有值,因为只有在实际调用该函数时才会生成新对象。您可以编译该表达式,调用它并序列化结果,或者您可以序列化构造函数调用本身 - 类似于您序列化该服务调用的方式。
请注意,{ "Name": "check" }
和{ "ID": 2 }
缺少类型信息。
答案 1 :(得分:1)
我结合了this answer和Pieter Witvoet的答案中的信息,并收到了以下功能:
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());
}
}
现在,我可以简单地执行以下操作:
var args = mce.Arguments.Select(ExpressionEvaluator.Evaluate).ToArray();