2016-04-26 88 views
0

我不得不被描述爲以下遠程服務的調用:如何使用參數序列化方法調用表達式?

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",但不適用於usernew Entity { ID = 2 }),因爲它們分別是FieldExpressionNewExpression。如何獲得傳遞給函數調用的實際值,而不是它們的表達式表示?

更新:suggested duplicate question的答案是不合適的,因爲我不想編譯我的表達式並執行它 - 我只需要評估參數。

+0

從[獲取值的可能的複製ExpressionTrees](http://stackoverflow.com/questions/3457558/getting-values-from-expressiontrees) – yaakov

+0

你不能得到非常量值,因爲它們可以鏈接到閉包或方法調用參數,它們將被評估表達式執行期間。所以在不知道它們的情況下,很難獲得它們的實際值 –

回答

1

我,結合了來自this answer和彼得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(); 
1

FieldExpression一個具有Member(場)和Expression,在這種情況下ConstantExpression保持包含該字段的對象。這個常量表達式的Value是一個匿名對象,它捕獲本地變量user。通過將Member投射到FieldInfo,您可以對其調用GetValue,並且通過傳遞該常量表達式的Value,您將獲得要查找的User對象。

A NewExpression有一個ConstructorArguments屬性(表達式列表),但沒有值,因爲只有在實際調用該函數時纔會生成新對象。您可以編譯該表達式,調用它並序列化結果,或者可以序列化構造函數調用本身 - 類似於序列化該服務調用的方式。

請注意,{ "Name": "check" }{ "ID": 2 }缺少類型信息。

+0

可以忽略類型信息,因爲我將根據服務方法參數的類型使用反射並反序列化它們。 –

+0

非常感謝您的幫助。我有[組合](http://stackoverflow.com/a/36862531/3218692)你的答案與另一個,現在一切正常。 –

+0

@YeldarKurmangaliyev:關於類型信息,我假設你不打算支持子類化這些參數類型? –

相關問題