2016-04-03 101 views
1

我試圖將一個對象與一個隨機值進行比較,該值可能是一個ID和ObjectKey,甚至是同一個對象。總之,我想比較一個對象與任何東西,而不只是相同的類型。使用ExpressionVisitor將'obj == value'更改爲'obj.Equals(value)'

爲此,我覆蓋了對象的Equals()和GetHashCode(),並且它按預期工作。但我注意到當我通過'obj == value'搜索時,Linq不會調用這些方法。

如果我將查詢更改爲'obj.Equals(value)',則應該調用Equals()方法。但這不是我所需要的。此外,我試圖重載'=='和'!='操作符,但是當我通過接口搜索時,這些重載不會被調用。

最後,我不能手動更改所有查詢,因爲有人可能在將來的任何地方使用'==',破壞代碼。

所以我來ExpressionVisitor。我注意到我可以重寫我的Linq查詢的表達式,但我有點無知。我嘗試了一些我發現的例子,但是我遇到了一些錯誤。

最後,這是我經由ExpressionVisitor需要:

替換此: VAR對象= ctx.Where(OBJ => OBJ ==值);

to this: var objects = ctx.Where(obj => obj.Equals(value));

可能嗎?

回答

0

耶。發現它:

class Program 
{ 
    static void Main(string[] args) 
    { 
     //the sample: 
     Expression<Func<string, bool>> expr = name => name == "AA" || name.Length > 0 || name != "b"; 
     Console.WriteLine(expr); 
     EqualsModifier treeModifier = new EqualsModifier(); 
     Expression modifiedExpr = treeModifier.Modify((Expression)expr); 
     Console.WriteLine(modifiedExpr); 
     Console.ReadLine(); 
    } 
} 
//the ExpressionVisitor 
public class EqualsModifier : ExpressionVisitor 
{ 
    public Expression Modify(Expression expression) 
    { 
     return Visit(expression); 
    } 
    protected override Expression VisitBinary(BinaryExpression b) 
    { 
     if (b.NodeType == ExpressionType.Equal) 
     { 
      Expression left = this.Visit(b.Left); 
      Expression right = this.Visit(b.Right); 
      MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) }); 
      return Expression.Call(left, equalsMethod, right); 
     } 
     else if (b.NodeType == ExpressionType.NotEqual) 
     { 
      Expression left = this.Visit(b.Left); 
      Expression right = this.Visit(b.Right); 
      MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) }); 
      return Expression.Not(Expression.Call(left, equalsMethod, right)); 
     } 
     return base.VisitBinary(b); 
    } 
} 

這些所有的輸出:

原件:! 名稱=>(((名稱== 「AA」)OrElse運算(name.Length < 0))OrElse運算(名稱=「 b 「))

轉換: 名稱=>((name.Equals(」 AA 「)OrElse運算(name.Length < 0))OrElse運算不是(name.Equals(」 b「)))

0

這是可能的。您可以編寫一個代理查詢提供程序,在重寫表達式後將該查詢傳遞給實際提供程序。

你也可以追求「LinqKit」與它的AsExpandable重寫器一起使用的方法。這種方法非常簡單,但需要將這些調用插入到每個查詢中。

您也可以使用Roslyn來執行源代碼的一次性重構。這樣做的缺點是源代碼對於那些Equals調用看起來不太好。

我沒有必要的時間來描繪這些解決方案,因爲它們有很多工作。對於AsExpandable,您可以在網上找到工作代碼。我相信也有編寫LINQ提供者的教程。

相關問題