2015-10-14 58 views
0

我想向表達式樹添加一個額外的方法調用,但是我很困惑如何實現它。以下是我目前正在工作:在表達式樹中調用有條件的方法

private static Action<object, object> CreateSetter(SetterInfo info) 
    { 
     var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 

     if (propertyInfo == null) 
      return (s, v) => { }; 

     var objParameter = Expression.Parameter(typeof(object)); 
     var valueParameter = Expression.Parameter(typeof(object)); 

     //This is the method call I'm trying to add 
     if (info.Name[0] == 'G' && info.Type.Name == TaxDataConstant.ParcelFeat) 
     { 
      var convertParcelFeatCall = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));   
     } 

     var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, Expression.Constant(propertyInfo.PropertyType)); 

     var objCast = Expression.Convert(objParameter, info.Type); 
     var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType); 

     var property = Expression.Property(objCast, propertyInfo); 

     var assignment = Expression.Assign(property, valueCast); 

     var lambda = Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter); 

     return lambda.Compile(); 
    } 

我希望發生的是:

1)如果我SetterInfo對象類型的名稱是ParcelFeat和屬性名以「G '我想調用valueParameter上的ConvertParcelFeat,然後在返回時調用ChangeType。

2)如果類型的名稱超過ParcelFeat調用一changeType正常其他任何與出額外的步驟

我感到困惑的是如何建立的條件。我假設我在上面的代碼中做的方式是錯誤的,我需要使用類似Expression.IfThen()來構建條件。我也不確定如何像我想要的那樣鏈接方法調用。

+0

你不Expression.IfThen需要,因爲每個特定SetterInfo你把只有一個特定的λ例如 – Victor

+0

只需插入convertParcelFeatCall在ExpressionTree和所有適當的地方應該工作得很好 – Victor

回答

1

您不需要在Expression.IfThen,因爲對於每個特定的SetterInfo,只需組合一個特定的lambda實例。

只需在您的ExpressionTree的適當位置插入convertParcelFeatCall,並且所有應用都可以正常工作。

所以你的代碼可能是這樣的:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var program = new Program(); 

     var weightLambda = program.DoInternal("Weight").ToString() 
      == "(Param_0, Param_1) => (Convert(Param_0).Weight = Convert(ChangeType(Param_1, System.Object)))"; 

     var goodiesLambda = program.DoInternal("Goodies").ToString() 
      == "(Param_0, Param_1) => (Convert(Param_0).Goodies = Convert(ChangeType(Param_1, ConvertParcelFeat(Param_1, \"Goodies\"))))"; 

     Console.WriteLine("WeightLambda is Ok: {0}\nGoodiesLambda is Ok: {1}", weightLambda, goodiesLambda); 
    } 

    public Action<Object, Object> Do(string name) 
    { 
     return DoInternal(name).Compile(); 
    } 

    public Expression<Action<object, object>> DoInternal(string name) 
    { 
     var info = new {Name = name, Type = typeof(Program)}; 
     var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 

     var objParameter = Expression.Parameter(typeof(object)); 
     var valueParameter = Expression.Parameter(typeof(object)); 

     //This is the method call I'm trying to add 
     Expression toBeTypeChanged; 
     if (info.Name[0] == 'G' && info.Type.Name == "Program") 
     { 
      toBeTypeChanged = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name)); 
     } 
     else 
     { 
      toBeTypeChanged = Expression.Constant(propertyInfo.PropertyType); 
     } 

     var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, toBeTypeChanged); 

     var objCast = Expression.Convert(objParameter, info.Type); 
     var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType); 

     var property = Expression.Property(objCast, propertyInfo); 

     var assignment = Expression.Assign(property, valueCast); 

     return Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter); 
    } 

    public object Weight { get; set; } 
    public object Goodies { get; set; } 

    public static object ChangeType(object valueParameter, object constant) 
    { 
     return null; 
    } 

    public static object ConvertParcelFeat(object valueParameter, object constant) 
    { 
     return null; 
    } 

    public MethodInfo ConvertParcelFeatMethod 
    { 
     get { return typeof(Program).GetMethod("ConvertParcelFeat"); } 
    } 

    public MethodInfo ChangeTypeMethod 
    { 
     get { return typeof(Program).GetMethod("ChangeType"); } 
    } 
}