2011-02-27 59 views
1

UPDATE如何轉換表達式樹?

我會盡力解釋我的意思。 有2 不同類(MyClass1的和MyClass2)和方法的Class1轉換爲等級2:

class MyClass1 
    { 
     //...Some fields and properties 
} 

    class MyClass2 
    { 
     //...Some fields and properties 
    } 

public MyClass2 Convert(MyClass1 class1) 
{ 
//..... 
return class2Object; 
} 

有2點不同的方法:

void method1(Expression<Func<MyClass1, bool>> where, //other parameters) 
    { 
     //some operations 
     //............... 

     //need to call method2(Expression<Func<MyClass2, bool>>) 
     // BUT! How do I convert Expression<Func<MyClass1, bool>> 
     // to Expression<Func<MyClass2, bool>> 
    } 

    void method2(Expression<Func<MyClass2, bool>> where, //other parameters) 
    { 
     //some operations 
    } 

如何轉換表達< Func鍵< MyClass1,bool >>至表達式< Func < MyClass2,bool >>

+1

既然'MyClass1'和'MyClass2'不能互相轉換,你怎麼期望轉換委託? – 2011-02-27 12:08:43

+1

直到你定義'MyClass1'和'MyClass2'之間的顯式轉換,你甚至不能開始。 – 2011-02-27 12:09:16

+0

看看我的編輯。 – Alexandre 2011-02-27 12:14:32

回答

1

表達式樹是不可變的,所以要做到這一點,你需要遍歷整個樹,重建它,並用類似的方式取代類型的任何用途 - 通常通過編寫一個「訪問者」。當遇到MemberExpression或MethodCallExpression時,你可以檢查成員的聲明類型 - 如果它是你不想要的,重新創建它(Expression.PropertyOrField在這裏很有用)。

請注意,您不能僅在使用它的地方執行此操作;整棵樹必須重新生成。我目前不在PC上,但如果你想要,我可以稍後做一個例子;如果你需要這個例子,請留下評論。

請注意,這是由int/long和char/string不匹配有點複雜。

+0

是的,請。給我舉個例子。 – Alexandre 2011-02-27 20:29:20

6

讓我猜猜你問:你MyClass1MyClass2看起來一樣(它們都具有一個int FIELD1和一個字符串域2)。現在你有一個Expression<Func<MyClass1,bool>>,是這樣的:

Expression<Func<MyClass1, bool>> exp1 = x => x.field1 == 100; // x is MyClass1 

你想要的另一種表達,這看起來是一樣的,但它是爲MyClass2

Expression<Func<MyClass2, bool>> exp2 = x => x.field1 == 100; // x is MyClass2 

如果這是你在問什麼,在這裏就是我的回答:

要得到表達式MyClass2,你需要替換exp1所有x,因爲所有exp1中的是MyClass1ExpressionVisitor正是你想要的。

class MyExpressionVisitor : ExpressionVisitor 
{ 
    public ParameterExpression NewParameterExp { get; private set; } 

    public MyExpressionVisitor(ParameterExpression newParameterExp) 
    { 
     NewParameterExp = newParameterExp; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     return NewParameterExp; 
    } 

    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (node.Member.DeclaringType == typeof(MyClass1)) 
      return Expression.MakeMemberAccess(this.Visit(node.Expression), 
       typeof(MyClass2).GetMember(node.Member.Name).FirstOrDefault()); 
     return base.VisitMember(node); 
    } 
} 

訪問者將通過(稱爲「訪問」)整個表達式,訪問所有節點。當涉及到一個​​節點時,我們更改節點(因爲它是MyClass1,我們將其更改爲MyClass2,請參閱VisitParameter方法)。我們需要改變的另一件事是,當訪問者訪問像x.field1這樣的節點時,它正在訪問MyClass1中的field1,我們也需要修改它(請參閱VisitMember)。在經歷了整個exp1之後,我們得到了一個全新的exp2,並且更換了一些節點,這就是我們想要的。

Expression<Func<MyClass1, bool>> exp1 = x => x.field1 == 100; 

var visitor = new MyExpressionVisitor(Expression.Parameter(typeof(MyClass2), 
         exp1.Parameters[0].Name)); 

var exp2 = Expression.Lambda<Func<MyClass2, bool>> 
       (visitor.Visit(exp1.Body), visitor.NewParameterExp); 

//the following is for testing 
var data = new MyClass2(); 
Console.WriteLine(exp2.Compile()(data)); //False 
data.field1 = 100; 
Console.WriteLine(exp2.Compile()(data)); //True 
+0

感謝您的回答,但這不是我的意思。 – Alexandre 2011-02-27 18:10:39

+2

@Alex那麼如何描述你的意思? – CodesInChaos 2011-02-27 18:14:27

+0

我編輯了我的問題。 – Alexandre 2011-02-27 18:17:05

0
public CategoryViewModel GetSingle(Expression<Func<CategoryViewModel, bool>> where) 
     { 
      Expression<Func<DAL.EntityModels.Category, CategoryViewModel>> converter = 
       c => ToBll(c); 

      var param = Expression.Parameter(typeof(DAL.EntityModels.Category), "category"); 
      var body = Expression.Invoke(where, Expression.Invoke(converter, param)); 
      var lambda = Expression.Lambda<Func<DAL.EntityModels.Category, bool>>(body, param); 

      return (CategoryViewModel)_categoryRepository.GetSingle(lambda); 

     } 

//.............. 
public T GetSingle(Expression<Func<T, bool>> where) 
     { 
      return this.ObjectSet.Where(where).FirstOrDefault<T>(); 
     }