2013-04-09 41 views
1

位背景:我正在使用IQToolkit編寫使用System.Data.Odbc而不是System.Data.SqlClient的自定義數據提供程序。最簡單的方法來更改一個方法的行爲而不更改類?

我遇到了默認參數器類的問題,找到here。下面的代碼片段是我需要改變的,僅僅是一種方法。

int iParam = 0; 
    protected override Expression VisitConstant(ConstantExpression c) 
    { 
     if (c.Value != null && !IsNumeric(c.Value.GetType())) { 
      NamedValueExpression nv; 
      TypeAndValue tv = new TypeAndValue(c.Type, c.Value); 
      if (!this.map.TryGetValue(tv, out nv)) { // re-use same name-value if same type & value 
       string name = "p" + (iParam++); 
       nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c); 
       this.map.Add(tv, nv); 
      } 
      return nv; 
     } 
     return c; 
    } 

我想過的幾種方法,我可以做到這一點,但我真的不喜歡任何人。

  1. 我有源代碼,所以我可以更改源代碼本身並重新編譯它。但是,這會爲其他SQL方言刪除一些有用的代碼,我不想爲了ODBC而毀掉所有這些。

  2. 我可以寫我自己的Parameterizer類,並使用它來代替默認值。如果我這樣做,我會重複250行代碼,以便更改三個或四個。

  3. 我可以嘗試重寫該類,只更改我需要的方法。我嘗試過這個,但是我遇到了Parameterizer課程中的保護級別問題。我喜歡這個最好的,但我不確定我是否做得很對,或者我甚至可以用給定的課程設計。

道歉,如果這個問題似乎是模糊的,但對我有任何簡單的方法來改變方法的行爲,而不必更改基類或不復制其所有的代碼?

編輯:與#3問題:無法訪問IsNumeric(私有Parameterizer),無法訪問Parameterizer.map,不能訪問結構TypeAndValue,不能訪問Parameterizer.language

+0

你遇到了什麼問題與選項#3?這對我來說似乎也是最好的選擇。 – Adrian 2013-04-09 18:24:35

+0

@Adrian查看我的編輯。 'Parameterizer'中的所有保護級別問題。 – Mansfield 2013-04-09 18:28:26

+0

我可能會關閉 - 但如果這是「訪問者」,那麼您可以實現自己的訪問者 - 除了「VisitConstant」之外,其他所有訪問者都可以調用默認的訪問者 - 然後實現該訪問者。 – NSGaga 2013-04-09 18:29:02

回答

0

它最終只是更容易重寫參數器。不確定這是否廣泛相關,但我必須更改代碼,以防萬一有興趣:

此方法的問題在於它試圖重複使用具有重複類型和值的參數。但是,由於我使用的是未命名的ODBC樣式參數,因此查詢必須具有與查詢指定的相同數量的參數,即使它們完全相同。

protected override Expression VisitConstant(ConstantExpression c) 
{ 
    if (c.Value != null && !IsNumeric(c.Value.GetType())) { 
     NamedValueExpression nv; 
     TypeAndValue tv = new TypeAndValue(c.Type, c.Value, iParam); 

     string name = "p" + (iParam++); 
     nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c); 
     this.map.Add(tv, nv); 

     return nv; 
    } 
    return c; 
} 

我也不得不修改TypeAndValue構造使哈希值唯一,即使它們的類型和值是相同的參數。我通過添加參數號來完成。

public TypeAndValue(Type type, object value, int pCount) 
{ 
    this.type = type; 
    this.value = value; 
    this.hash = type.GetHashCode() + (value != null ? value.GetHashCode() : 0) + pCount; 
} 
2

例如像這樣的東西就是我的想法(根據我們的意見)。

public class MyVisitor : DbExpressionVisitor 
{ 
    // cast it to the visitor interface/base - that way you'd have access to all methods, 
    // as Parameterizer has to have them publically exposed anyway, for this to work 
    readonly DbExpressionVisitor _defaultVisitor; 
    public MyVisitor() 
    { 
     _defaultVisitor = new Parameterizer(); 
    } 
    public Expression VisitProjection(ProjectionExpression proj) 
    { 
     return _defaultVisitor.Visit(proj); 
    } 
    // ...same for all others, just... 
    // ... 

    // implement your own for one 'route' 
    protected Expression VisitConstant(ConstantExpression c) 
    { 
     if (c.Value != null && !IsNumeric(c.Value.GetType())) { 
      NamedValueExpression nv; 
      TypeAndValue tv = new TypeAndValue(c.Type, c.Value); 
      if (!this.map.TryGetValue(tv, out nv)) { // re-use same name-value if same type & value 
       string name = "p" + (iParam++); 
       nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c); 
       this.map.Add(tv, nv); 
      } 
      return nv; 
     } 
     return c; 
    } 
} 

遊客,訪問者模式 ...

「從本質上說,訪問者允許一個新的虛擬功能添加到 類家族,而無需修改類本身」

即這意味着在大多數情況下,它自己就足夠了,不需要求助於繼承,覆蓋(它有點冗餘,有點簡化)。你可以使用這個事實來覆蓋原始訪問者的某些行爲(因爲你已經有了一個機制) - 並且避免繼承和你可能遇到的問題。

唯一可能的問題與這可能是 - 該Parameterizer 沒有默認的構造函數 - 這是不太可能,我認爲你 可能需要反正。

+0

我不太明白這一點 - 從這看起來我不得不修改原始源代碼以使'Parameterizer'實現一個接口 - 是否正確? – Mansfield 2013-04-09 18:45:22

+0

nope @Mansfield - 我在這裏給你一個'僞代碼' - IVisitor是你的'DbExpressionVisitor' - 你實現了 - VS會自動執行並提供10/20空白方法 - 你只需要添加'return _defaultVisitor 。訪問(e);'(或不返回我不知道的) - 只是你需要的一個「implmenet」。 – NSGaga 2013-04-09 18:48:17

+0

我犯了很多錯誤匆忙:)但我認爲現在看起來好了 – NSGaga 2013-04-09 18:51:45

相關問題