Tôi là making a jquery clone cho C#. Ngay bây giờ tôi đã thiết lập nó sao cho mọi phương thức là một phương thức mở rộng trên IEnumerable<HtmlNode>
để nó hoạt động tốt với các dự án hiện có đang sử dụng HtmlAgilityPack
. Tôi nghĩ rằng tôi có thể nhận được đi mà không cần bảo quản nhà nước ... tuy nhiên, sau đó tôi nhận thấy jQuery có hai phương pháp .andSelf
và .end
mà "pop" các yếu tố phù hợp gần đây nhất ra khỏi một ngăn xếp nội bộ. Tôi có thể bắt chước chức năng này nếu tôi thay đổi lớp của mình để nó luôn hoạt động trên các đối tượng SharpQuery thay vì đếm, nhưng vẫn còn một vấn đề.Làm thế nào để thiết kế C# jQuery API của tôi như vậy mà nó không phải là khó hiểu để sử dụng?
Với JavaScript, bạn được cung cấp tài liệu Html tự động, nhưng khi làm việc trong C# bạn phải tải nó một cách rõ ràng và bạn có thể sử dụng nhiều tài liệu nếu muốn. Có vẻ như khi bạn gọi $('xxx')
, về cơ bản bạn đang tạo một đối tượng jQuery mới và bắt đầu mới với một chồng trống. Trong C#, bạn sẽ không muốn làm điều đó, bởi vì bạn không muốn tải lại/nạp lại tài liệu từ web. Vì vậy, thay vào đó, bạn tải nó một lần hoặc vào một đối tượng SharpQuery, hoặc vào một danh sách các HtmlNodes (bạn chỉ cần DocumentNode để bắt đầu).
Trong các tài liệu jQuery, họ đưa ra ví dụ này
$('ul.first').find('.foo')
.css('background-color', 'red')
.end().find('.bar')
.css('background-color', 'green')
.end();
Tôi không có một phương pháp khởi tạo bởi vì tôi không thể nạp chồng toán tử ()
, vì vậy bạn chỉ cần bắt đầu với sq.Find()
thay vào đó, mà hoạt động trên gốc của tài liệu, về cơ bản làm điều tương tự. Nhưng sau đó mọi người sẽ thử và viết sq.Find()
trên một dòng, và sau đó sq.Find()
ở đâu đó trên đường và (đúng) mong đợi nó hoạt động trên thư mục gốc của tài liệu một lần nữa ... nhưng nếu tôi duy trì trạng thái thì bạn vừa sửa đổi ngữ cảnh sau cuộc gọi đầu tiên.
Vậy ... tôi nên thiết kế API của mình như thế nào? Tôi có thêm phương thức Init
khác là tất cả các truy vấn nên bắt đầu bằng cách đặt lại ngăn xếp (nhưng sau đó làm cách nào để bắt buộc chúng bắt đầu bằng cách đó?) Hoặc thêm Reset()
mà chúng phải gọi ở cuối dòng? Tôi có quá tải các []
thay vào đó và nói với họ để bắt đầu với điều đó? Tôi có nói "quên nó đi, không ai sử dụng những chức năng được nhà nước bảo tồn đó không?"
Về cơ bản, bạn muốn viết ví dụ jQuery như thế nào trong C#?
sq["ul.first"].Find(".foo") ...
downfalls: Lạm dụng các[]
tài sản.sq.Init("ul.first").Find(".foo") ...
downfalls: Không có gì thực sự buộc các lập trình viên để bắt đầu với Init, trừ khi tôi thêm một số cơ chế "khởi tạo" lạ; người dùng có thể thử bắt đầu với.Find
và không nhận được kết quả mong đợi. Ngoài ra,Init
vàFind
là khá nhiều giống hệt nhau, ngoại trừ trước đây đặt lại ngăn xếp quá.sq.Find("ul.first").Find(".foo") ... .ClearStack()
downfalls: lập trình viên có thể quên để xóa các ngăn xếp.Không thể làm điều đó.
end()
không được triển khai.Sử dụng hai đối tượng khác nhau.
Có thể sử dụngHtmlDocument
làm cơ sở mà tất cả truy vấn sẽ bắt đầu bằng, và sau đó mọi phương thức sau đó trả về đối tượngSharpQuery
có thể bị xích. Bằng cách đó,HtmlDocument
luôn duy trì trạng thái ban đầu, nhưng đối tượngSharpQuery
có thể có các trạng thái khác nhau. Điều này không may có nghĩa là tôi phải thực hiện một loạt các công cụ hai lần (một lần cho HtmlDocument, một lần cho đối tượng SharpQuery).new SharpQuery(sq).Find("ul.first").Find(".foo") ...
Bản sao constructor một tham chiếu đến các tài liệu, nhưng reset stack.
IMO 5) là tùy chọn tốt nhất. Nó chắc chắn có thể đọc được và trực quan cho các truy vấn bắt đầu từ 'HtmlDocument', và đối với tác phẩm trùng lặp - hy vọng bạn có thể thực hiện nó sao cho chỉ các chữ ký phương thức được sao chép, chứ không phải logic thực tế. (Chaining các cuộc gọi đến một số lớp học phổ biến mà không công việc.) Tôi cũng thích tùy chọn 1) và cá nhân không nhìn thấy nó như là một "lạm dụng" của các dấu ngoặc đơn. :) –
@Kirk: '[]' thường chỉ ra thao tác 'O (1)' ... giống như dữ liệu đã được lập chỉ mục. Trong trường hợp này, nó thực sự phải thực hiện tìm kiếm đầy đủ. – mpen
Tuy nhiên, tôi đang hướng tới (1) ngay bây giờ. Trên thực tế, tôi đã bắt đầu viết mã theo cách này. Điều này ngăn người dùng nhảy ngay với '.Find()' vì bối cảnh không được đặt cho đến khi họ gọi '[]'. tức là '.Find()' đơn giản sẽ không tìm thấy bất kỳ thứ gì vì nó không có gì để tìm kiếm. '[]' đặt lại ngữ cảnh cho nút tài liệu và sau đó chúng có thể bắt đầu tìm kiếm. – mpen