5

C# 用の jquery クローンを作成しています。現在、すべてのメソッドが拡張メソッドになるようにセットアップしているので、IEnumerable<HtmlNode>既にHtmlAgilityPack. 状態を保存せずに逃げることができると思っていました...しかし、jQueryには2つのメソッドが.andSelfあり.end、最近一致した要素を内部スタックから「ポップ」することに気付きました。列挙型ではなく SharpQuery オブジェクトで常に動作するようにクラスを変更すると、この機能を模倣できますが、まだ問題があります。

JavaScript では Html ドキュメントが自動的に提供されますが、C# で作業する場合は明示的に読み込む必要があり、必要に応じて複数のドキュメントを使用できます。$('xxx')呼び出すと、本質的に新しい jQuery オブジェクトを作成し、空のスタックで新たに開始しているように見えます。C# では、Web からドキュメントをリロード/再取得したくないため、これを行いたくありません。代わりに、SharpQuery オブジェクトまたは HtmlNodes のリストに一度ロードします (開始するには DocumentNode が必要です)。

jQueryのドキュメントでは、彼らはこの例を示しています

$('ul.first').find('.foo')
  .css('background-color', 'red')
.end().find('.bar')
  .css('background-color', 'green')
.end();

()演算子をオーバーロードできないため、初期化メソッドはありません。sq.Find()代わりに、ドキュメントのルートで動作し、本質的に同じことから始めます。sq.Find()しかし、人々は1 行で書き込もうとし、その後sq.Find()どこかで書き込もうとし、(当然のことながら) ドキュメントのルートで再び動作することを期待します... しかし、私が状態を維持している場合、あなたは最初の呼び出しの後にコンテキストを変更しただけです。

では、API をどのように設計すればよいでしょうか? すべてのクエリがスタックをリセットする別のメソッドを追加するInit必要がありますか (しかし、それから強制的に開始するにはどうすればよいでしょうか?)、またはReset()、行の最後に呼び出さなければならない a を追加しますか? 代わりにオーバーロードして、[]それから始めるように伝えますか? 「忘れてください、とにかく誰も状態保存関数を使用していません」と言いますか?

基本的に、その jQuery の例を C# でどのように記述しますか?

  1. sq["ul.first"].Find(".foo") ...
    落とし穴:[]プロパティを悪用します。

  2. sq.Init("ul.first").Find(".foo") ...
    落とし穴: 奇妙な「初期化」メカニズムを追加しない限り、プログラマーに Init を開始することを実際に強制するものは何もありません。ユーザーは最初から試してみて.Findも、期待した結果が得られない可能性があります。また、Init前者Findもスタックをリセットすることを除いて、とにかくほとんど同じです。

  3. sq.Find("ul.first").Find(".foo") ... .ClearStack()
    欠点: プログラマーがスタックをクリアするのを忘れる可能性があります。

  4. できません。
    end()実装されていません。

  5. 2 つの異なるオブジェクトを使用します。
    おそらくHtmlDocument、すべてのクエリを開始するベースとして使用すると、その後のすべてのメソッドSharpQueryが連鎖可能なオブジェクトを返します。このように、 はHtmlDocument常に初期状態を維持しますが、SharpQueryオブジェクトは異なる状態になる場合があります。これは残念ながら、たくさんのものを 2 回 (HtmlDocument に対して 1 回、SharpQuery オブジェクトに対して 1 回) 実装する必要があることを意味します。

  6. new SharpQuery(sq).Find("ul.first").Find(".foo") ...
    コンストラクターはドキュメントへの参照をコピーしますが、スタックをリセットします。

4

2 に答える 2

4

SharpQueryここで遭遇している主な障害は、ドキュメントごとに1つのオブジェクトを用意するだけで解決しようとしていることだと思います。これはjQueryの仕組みではありません。一般に、jQueryオブジェクトは不変です。find要素のセット(またはendまたは)を変更するメソッドを呼び出すとadd、既存のオブジェクトは変更されませんが、新しいオブジェクトが返されます。

var theBody = $('body');
// $('body')[0] is the <body>
theBody.find('div').text('This is a div');
// $('body')[0] is still the <body>

(詳細については、のドキュメントをend参照してください)

SharpQueryは同じように動作するはずです。ドキュメントを使用してSharpQueryオブジェクトを作成すると、メソッド呼び出しはSharpQuery、同じドキュメントの異なる要素のセットを参照して、新しいオブジェクトを返す必要があります。例えば:

var sq = SharpQuery.Load(new Uri("http://api.jquery.com/category/selectors/"));
var header = sq.Find("h1"); // doesn't change sq
var allTheLinks = sq.Find(".title-link") // all .title-link in the whole document; also doesn't change sq
var someOfTheLinks = header.Find(".title-link"); // just the .title-link in the <h1>; again, doesn't change sq or header

このアプローチの利点はいくつかあります。、、、などはすべて同じクラスであるため、各メソッドの実装は1つだけですsq。ただし、これらの各オブジェクトは同じドキュメントを参照するため、各ノードの複数のコピーはなく、ノードへの変更はそのドキュメントのすべてのオブジェクトに反映されます(たとえば、。の後)。headerallTheLinksSharpQueryallTheLinks.text("foo")someOfTheLinks.text() == "foo"

実装endやその他のスタックベースの操作も簡単になります。各メソッドは、別のメソッドから新しいフィルター処理されたSharpQueryオブジェクトを作成するときに、その親オブジェクトへの参照(allTheLinksto headerheaderto sq)を保持します。次に、次のように、親と同じ要素を含むendnewを返すのと同じくらい簡単です。SharpQuery

public SharpQuery end()
{
    return new SharpQuery(this.parent.GetAllElements());
}

(または、構文が揺らいでいます。)

このアプローチにより、実装がかなり簡単で、jQueryに最も似た動作が得られると思います。私は間違いなくこのプロジェクトに目を光らせています。それは素晴らしいアイデアです。

于 2010-11-07T18:51:47.867 に答える
0

オプション 2 のバリアントに傾倒します。jQuery では $() は関数呼び出しです。C# にはグローバル関数がありません。静的関数呼び出しが最も近いです。..のようなラッパーを作成していることを示す方法を使用します。

SharpQuery.Create("ul.first").Find(".foo")

インテリセンスはユーザーがすべてを入力する必要がないことを意味するため、SharpQuery を sq に短縮することについて心配する必要はありません (また、リシャーパーを使用している場合は、とにかく SQ を入力するだけで済みます)。

于 2010-11-06T23:23:45.207 に答える