我正在为 C#制作一个 jquery 克隆。现在我已经把它设置好了,每个方法都是一个扩展方法,IEnumerable<HtmlNode>
所以它可以很好地与已经使用的现有项目一起工作HtmlAgilityPack
。我以为我可以在不保留状态的情况下逃脱……但是,然后我注意到 jQuery 有两种方法.andSelf
,.end
它们将最近匹配的元素从内部堆栈中“弹出”。如果我更改我的类以便它始终在 SharpQuery 对象而不是枚举对象上运行,我可以模仿这个功能,但仍然存在问题。
使用 JavaScript,您会自动获得 Html 文档,但在使用 C# 时,您必须显式加载它,如果您愿意,可以使用多个文档。看来,当您调用时,$('xxx')
您实际上是在创建一个新的 jQuery 对象并从一个空堆栈重新开始。在 C# 中,您不想这样做,因为您不想从 Web 重新加载/重新获取文档。因此,您只需将其加载到 SharpQuery 对象或 HtmlNode 列表中(您只需要 DocumentNode 即可开始)。
在 jQuery 文档中,他们给出了这个例子
$('ul.first').find('.foo')
.css('background-color', 'red')
.end().find('.bar')
.css('background-color', 'green')
.end();
我没有初始化方法,因为我不能重载()
运算符,所以你只需从它开始sq.Find()
,它在文档的根目录上运行,基本上做同样的事情。但是然后人们会尝试sq.Find()
在一行上写,然后在sq.Find()
某个地方,并且(正确地)期望它再次在文档的根目录上运行......但如果我保持状态,那么你已经刚刚在第一次调用后修改了上下文。
那么......我应该如何设计我的 API?我是否添加了另一种Init
方法,所有查询都应该以重置堆栈开始(但是我如何强制它们开始呢?),或者添加一个Reset()
他们必须在行尾调用的方法?我是否要重载[]
而不是告诉他们从那开始?我会说“算了吧,反正没人使用那些状态保留的函数吗?”
基本上,您希望如何用 C# 编写 jQuery 示例?
sq["ul.first"].Find(".foo") ...
缺点:滥用[]
财产。sq.Init("ul.first").Find(".foo") ...
缺点:没有什么能真正迫使程序员从 Init 开始,除非我添加一些奇怪的“初始化”机制;用户可能会尝试开始,.Find
但没有得到他期望的结果。而且,Init
无论如何Find
都几乎相同,除了前者也重置堆栈。sq.Find("ul.first").Find(".foo") ... .ClearStack()
缺点:程序员可能会忘记清除堆栈。做不到。
end()
未实现。使用两个不同的对象。
也许使用HtmlDocument
作为所有查询应该开始的基础,然后每个方法都返回一个SharpQuery
可以链接的对象。这样,HtmlDocument
始终保持初始状态,但SharpQuery
对象可能具有不同的状态。不幸的是,这意味着我必须两次实现一堆东西(一次用于 HtmlDocument,一次用于 SharpQuery 对象)。new SharpQuery(sq).Find("ul.first").Find(".foo") ...
构造函数复制对文档的引用,但重置堆栈。