将类型推断与流畅的接口结合使用
我有一个类/接口层次结构。在接口方面我有
IQuery
ISelect (inherits IQuery)
IUpdate (inherits IQuery)
etc
在类方面我有
QueryBase (implements IQuery)
SelectQuery (implements ISelect)
UpdateQuery (implements IUpdate)
etc
显然,例如,Update 和 Select 类共享一个 WHERE 子句,但只有 Select 具有 GROUP BY 功能,因此理想情况下,如果正在创建 Update 查询,流畅的接口将不会给出访问 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;
}
,并带有 QueryBase 上的 Friend(内部)方法 SetWhere,以允许我更新 WHERE 子句。但是,由于泛型仅限于 IQuery,因此它无法找到 SetWhere。但是,如果我约束为 QueryBase,那么显然编译器会抛出错误,指出 ISelect 找不到 AddWhere 方法。
我认为我还没有完全正确地实现我想要实现的目标的继承链或接口实现。
(我希望这一点很清楚!!)
如果有人能建议我在扩展方法实现方面出错的地方,或者我应该如何更好地构建我的类/接口层次结构,我将不胜感激。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
也许您可以在层次结构中使用另一个接口,例如:
IConditional
接口可以具有AddWhere
方法,可以直接在接口定义中,也可以作为约束的扩展方法IConditional
类型。Perhaps you could use another interface in your hierarchy, something like:
The
IConditional
interface could then have theAddWhere
method, either directly in the interface definition or as an extension method constrained on theIConditional
type.