I have a class /interface hierarchy. On the interface side I have
IQuery
ISelect (inherits IQuery)
IUpdate (inherits IQuery)
etc
On the class side I have
QueryBase (implements IQuery)
SelectQuery (implements ISelect)
UpdateQuery (implements IUpdate)
etc
Obviously, for example, both Update and Select classes share a WHERE clause but only a Select has GROUP BY functionality so ideally if an Update Query is being creating, the fluent interface will not give access to GROUP BY functionality but would do if a SelectQuery was being created.
eg in fluent interface terms
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
I am unsure how to implement the AddWhere function.
Previously I had declared the AddWhere function in the IQuery interface as
Function AddWhere(ByVal condition As ICriterion) As IQuery
IQuery AddWhere(ICriterion condition)
but because it was returning an IQuery, I was losing the benefits of the type inference and so as soon as the fluent interface had cast to the IQuery, if it was a Select query being created, I would no longer have access to, eg, the AddGroupBy method.
So I have tried to implement it as an Extension Method with generics
<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;
}
with a Friend (internal) method, SetWhere, on QueryBase to permit me to update the WHERE clause. However because the generic is constrained to IQuery, it won't find the SetWhere. However, if I constrain as QueryBase, then, obviously, the compiler throws wobblies saying that the ISelect can't find an AddWhere method.
I'm thinking that I haven't quite got the inheritence chain or interface implementations quite right for what I'm trying to achieve.
(I hope that is clear!!)
I'd be grateful if someone could suggest either where I am going wrong in terms of the extension method implementation, or how I should better structure my class/interface hierarchy.
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
Perhaps you could use another interface in your hierarchy, something like:
interface IQuery
interface IConditional : IQuery
interface ISelect : IConditional
interface IUpdate : IConditional
The IConditional
interface could then have the AddWhere
method, either directly in the interface definition or as an extension method constrained on the IConditional
type.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.