2012-02-17 2 views
4

У меня есть иерархия классов/интерфейсов. На стороне интерфейса у меня естьИспользование вывода типа с текущими интерфейсами

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

На стороне класса у меня есть

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

Очевидно, например, как обновление и выберите классы совместно ИНЕКЕ, но только Select имеет 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.

Ранее я объявил функцию AddWhere в интерфейсе IQuery, как

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 разрешить мне обновить ИНЕК. Однако, поскольку общий параметр ограничен IQuery, он не найдет SetWhere. Однако, если я ограничусь как QueryBase, то, очевидно, компилятор бросает wobblies, говоря, что ISelect не может найти метод AddWhere.

Я думаю, что я не совсем понял цепочку наследования или реализации интерфейса, совершенно подходящую для того, чего я пытаюсь достичь.

(я надеюсь, что это понятно !!)

Я бы признателен, если кто-то может предложить либо где я неправильно с точки зрения реализации метода расширения, или как я должен лучше структурировать мой класс/интерфейс иерархия.

+1

Я думаю http://stackoverflow.com/questions/1723648/how-to-inherit-method-but-with-different-return-type может быть полезно прочитать, поскольку он обсуждает упрощенную форму того, что вы пытается. В основном это говорит о том, что это невозможно, хотя есть несколько обходных решений, включая создание базовых классов Generic. Я думаю, что эта последняя часть (ответ dtb), вероятно, сделает то, что вы хотите, если вы довольны реструктуризацией вашего кода. – Chris

+0

Крис: Я немного поиграл с этим. Это q говорит только о конкретных классах, и мне интересно, сложна ли моя сценария иерархией интерфейса.Я попытался обобщить QueryBase на QueryBase (из T как IQuery), но это означало бы, что AFYICS, что мой, например, «фабрика SelectQuery», должен был бы вернуть либо SelectQuery, либо QueryBase (из ISelect), а не ISelect. Аналогичным образом, беглым методам необходимо будет возвращать бетоны. Я возвращал чистые интерфейсы из-за ISP/простоты насмешек. Я что-то упускаю? –

+0

Боюсь, я не знаю. Я знаю, что вопрос был несколько иным и нуждался в некоторой адаптации, если бы он работал, но я этого не делал раньше, и у меня нет времени играть с ним сам. Возможно, эти вопросы не помогут вам решить все, я просто надеялся. ;-) – Chris

ответ

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 –

+0

Добро пожаловать. Я не понимал, сколько лет прошло, пока я не ответил. Рад, что это по-прежнему полезно. –

0

Может быть, вы могли бы использовать другой интерфейс в иерархии, что-то вроде:

interface IQuery 

interface IConditional : IQuery 

interface ISelect : IConditional 

interface IUpdate : IConditional 

Интерфейс IConditional может затем метод AddWhere, либо непосредственно в определении интерфейса или как метод расширения стесненного на IConditional типа ,

+0

Что бы вернуть AddWhere? В этой ситуации все равно придется возвращать Iquery или IConditional? – Chris

+0

Повторяя свой вопрос, есть ли причина, по которой 'AddWhere' должна появиться перед' AddGroupBy' для Select? И что вы в конечном итоге хотите вернуть? Мне кажется, что ваш var будет иметь тип 'IQuery', который затем имеет какой-то метод выполнения, правильно? –

+0

Я подозреваю, что все, что угодно, ответ, есть какая-то причина, почему он не должен был раньше? Я считаю, что методы возвращают тот же объект, на котором они были запущены, поэтому, если вы запустите метод на ISelect, вы должны получить ISelect, а не IQuery. Есть способы, если вы должны были ограничить AddWhere до последней вещи, но это было бы не совсем свободно (например, потому что тогда у вас был бы доступ к другому набору методов). Я должен также отметить, что я не являюсь оригинальным плакатом, поэтому мои взгляды могут быть не их взглядами. :) – Chris

Смежные вопросы