2012-02-17 52 views
4

我有一個類/接口層次結構。在接口方面我有流利的接口使用類型推斷

IQuery 
    ISelect  (inherits IQuery) 
    IUpdate  (inherits IQuery) 
    etc 

在課程方面我有

QueryBase  (implements IQuery) 
    SelectQuery (implements ISelect) 
    UpdateQuery (implements IUpdate) 
    etc 

很明顯,例如,無論是更新和選擇類共享一個WHERE子句,但只有一個選擇具有GROUP BY功能,因此最好如果正在創建更新查詢,則流暢接口將不會授予對GROUP BY功能的訪問權限,但是如果正在創建SelectQuery,則會執行該功能。

例如,在流暢的界面方面

var/Dim select = New SelectQuery()  <- returns ISelect explicit 
          .AddColumn(....) <- returns ISelect explicit 
          .AddWhere(....) <- returns ISelect inferred 
          .AddGroupBy(....) <- returns ISelect explicit 

    var/Dim update = New UpdateQuery()  <- returns IUpdate explicit 
          .AddSet(....)  <- returns IUpdate explicit 
          .AddWhere(....) <- returns IUpdate inferred 

我不能確定如何實現AddWhere功能。

以前我曾宣佈在IQUERY接口AddWhere功能

Function AddWhere(ByVal condition As ICriterion) As IQuery 

IQuery AddWhere(ICriterion condition) 

,但因爲它是返回一個IQUERY,我失去了類型推斷的好處,因此只要一口流利的接口已經投到IQuery,如果它是一個Select查詢被創建,我將不再有權訪問例如AddGroupBy方法。

所以我試圖與仿製藥

<Extension> 
Public Function AddWhere(Of T As IQuery)(Byval this as T, Byval condition as Condition) as T 
    this.SetWhere(condition) 
    Return Me 
End Function 

public T AddWhere<T>(T @this, Condition condition) where T : IQuery 
{ 
    @this.SetWhere(condition); 
    return this; 
} 

與朋友分享(內部)方法,SetWhere實現它作爲一個擴展方法,對QueryBase允許我更新的WHERE子句。但是,由於泛型限制爲IQuery,它不會找到SetWhere。但是,如果我將其約束爲QueryBase,那麼顯然,編譯器會拋出異議,說ISelect找不到AddWhere方法。

我在想,我還沒有完全得到我想要實現的繼承鏈或接口實現。

(我希望這是明確的!)

我會很感激,如果有人可以建議要麼我在哪裏的擴展方法實現,或者我應該如何更好地安排我的類/接口方面腳麻層次結構。

+1

我覺得,因爲它討論的是你一個簡單的形式http://stackoverflow.com/questions/1723648/how-to-inherit-method-but-with-different-return-type可能是有用的閱讀正在嘗試。它主要說它不可能,儘管有幾個解決方法,包括使您的基類Generic。我認爲如果你對代碼重組感到滿意,最後一部分(dtb的答案)可能會做你想做的。 – Chris 2012-02-17 11:04:13

+0

克里斯我玩了一下。那個q只和具體的類對話,我想知道我的場景是否也被一個接口層次結構複雜化了。我試圖將QueryBase通用化爲QueryBase(T作爲IQuery),但那意味着,AFAICS,我的例如「SelectQuery工廠」將需要返回SelectQuery或QueryBase(的ISelect)而不是ISelect。同樣,流利的方法也需要返回混凝土。由於ISP /易於嘲弄,我返回純粹的接口。我錯過了什麼嗎? – 2012-02-18 12:49:45

+0

恐怕我不知道。我知道這個問題稍微有點不同,如果它能夠工作,需要做一些調整,但我之前沒有這樣做,也沒有時間自己去玩。可能這些問題不會幫助你完美地解決問題,我只是希望。 ;-) – Chris 2012-02-20 10:16:45

回答

1
Public Interface IQuery 
    Function AddWhere() As IQuery 
End Interface 

Public Interface IUpdate : Inherits IQuery 
    Overloads Function AddWhere() As IUpdate 
End Interface 

Public Interface ISelect : Inherits IQuery 
    Overloads Function AddWhere() As ISelect 
    Function AddGroupBy() As ISelect 
End Interface 

Public Class QueryBase : Implements IQuery 
    Public Function AddWhere() As IQuery Implements IQuery.AddWhere 
     ''... 
     Return Me 
    End Function 
End Class 

Public Class UpdateQuery : Inherits QueryBase : Implements IUpdate 
    Public Shadows Function AddWhere() As IUpdate Implements IUpdate.AddWhere 
     MyBase.AddWhere() 
     Return Me 
    End Function 
End Class 

Public Class SelectQuery : Inherits QueryBase : Implements ISelect 
    Public Shadows Function AddWhere() As ISelect Implements ISelect.AddWhere 
     MyBase.AddWhere() 
     Return Me 
    End Function 
    Public Function AddGroupBy() As ISelect Implements ISelect.AddGroupBy 
     ''... 
     Return Me 
    End Function 
End Class 
+0

優秀。 Thx Ian – 2012-03-27 15:44:05

+0

不客氣 - 在我回答之前,我沒有意識到問題的年齡。很高興它仍然有用。 – 2012-03-27 16:38:48

0

也許你可以在你的層次使用其他接口,這樣的:

interface IQuery 

interface IConditional : IQuery 

interface ISelect : IConditional 

interface IUpdate : IConditional 

IConditional接口可以再有AddWhere方法,直接在接口定義或限制在IConditional類型的擴展方法。

+0

AddWhere會返回什麼?在這種情況下,它仍然必須返回一個Iquery或一個IConditional? – Chris 2012-02-17 09:53:53

+0

再次通讀您的問題,是否有任何理由爲什麼'AddWhere'必須在選擇的AddGroupBy之前?另外你最終想要返回什麼?對我來說,這聽起來像你的var將是類型'IQuery',然後有某種執行方法,是否正確? – 2012-02-17 10:50:39

+0

我儘可能地懷疑答案是否有什麼理由不應該出現?流暢的東西的關鍵點是我相信這些方法返回它們運行的​​同一個對象,所以如果你在一個ISelect上運行一個方法,你應該返回一個ISelect,而不是IQuery。有幾種方法可以將AddWhere限制在最後,但它不會真正流暢(例如,因爲您可以訪問不同的方法)。我還應該注意到,我不是原始的海報,所以我的觀點可能不是他們的觀點。 :) – Chris 2012-02-17 10:54:15