Использование Вывода Типа с беглыми интерфейсами - PullRequest
4 голосов
/ 17 февраля 2012

У меня есть иерархия классов / интерфейсов. На стороне интерфейса у меня есть

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

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

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

Очевидно, например, что и классы Update, и классы Select совместно используют предложение WHERE, но только функция 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;
}

с методом Friend (внутренним) SetWhere в QueryBase, чтобы разрешить мне обновить предложение WHERE. Однако, поскольку универсальный ограничен IQuery, он не найдет SetWhere. Однако, если я ограничу как QueryBase, то, очевидно, компилятор выдаст колебания, говоря, что ISelect не может найти метод AddWhere.

Мне кажется, что я не совсем правильно понял цепочку наследования или реализации интерфейса для достижения моих целей.

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

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

Ответы [ 2 ]

1 голос
/ 27 марта 2012
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 голосов
/ 17 февраля 2012

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

interface IQuery

interface IConditional : IQuery

interface ISelect : IConditional

interface IUpdate : IConditional

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

...