2010-11-04 16 views
5

मैं सी # के लिए making a jquery clone हूं। अभी मुझे यह स्थापित हो गया है कि प्रत्येक विधि IEnumerable<HtmlNode> पर एक विस्तार विधि है, इसलिए यह मौजूदा परियोजनाओं के साथ अच्छी तरह से काम करती है जो पहले से ही HtmlAgilityPack का उपयोग कर रहे हैं। मैंने सोचा कि मैं राज्य को संरक्षित किए बिना दूर जा सकता हूं ... हालांकि, मैंने देखा कि jQuery में दो विधियां .andSelf और .end हैं जो एक आंतरिक ढेर से हाल ही में मिलान किए गए तत्वों को "पॉप" करती हैं। यदि मैं अपनी कक्षा बदलता हूं तो मैं इस कार्यक्षमता की नकल कर सकता हूं ताकि यह हमेशा संख्याओं के बजाय SharpQuery ऑब्जेक्ट्स पर चल रहा हो, लेकिन अभी भी एक समस्या है।मेरे सी # jQuery एपीआई को कैसे डिज़ाइन किया जाए ताकि यह उपयोग करने में भ्रमित न हो?

जावास्क्रिप्ट के साथ, आपको स्वचालित रूप से एचटीएमएल दस्तावेज़ दिया जाता है, लेकिन सी # में काम करते समय आपको इसे स्पष्ट रूप से लोड करना होगा, और यदि आप चाहें तो एक से अधिक दस्तावेज़ों का उपयोग कर सकते हैं। ऐसा प्रतीत होता है कि जब आप $('xxx') पर कॉल करते हैं तो आप अनिवार्य रूप से एक नई jQuery ऑब्जेक्ट बनाते हैं और खाली स्टैक के साथ ताजा शुरू करते हैं। सी # में, आप ऐसा नहीं करना चाहते हैं, क्योंकि आप वेब से दस्तावेज़ को पुनः लोड/रीफ्रैच नहीं करना चाहते हैं। तो इसके बजाय, आप इसे एक बार या तो SharpQuery ऑब्जेक्ट में लोड करते हैं, या HtmlNodes की सूची में लोड करते हैं (आपको प्रारंभ करने के लिए केवल दस्तावेज़ नोड की आवश्यकता होती है)।

jQuery डॉक्स में, वे इस उदाहरण

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

मैं, क्योंकि मैं () ऑपरेटर को ओवरलोड नहीं कर सकते एक प्रारंभकर्ता विधि की जरूरत नहीं है, इसलिए आप बस के बजाय sq.Find() के साथ शुरू है, जो पर चल रही देना दस्तावेज की जड़, अनिवार्य रूप से एक ही काम कर रही है। लेकिन फिर लोग एक लाइन पर sq.Find() को कोशिश करने और लिखने जा रहे हैं, और फिर sq.Find() सड़क के नीचे कहीं और, (सही ढंग से) उम्मीद है कि यह दस्तावेज़ की जड़ पर फिर से काम करेगी ... लेकिन अगर मैं राज्य को बनाए रख रहा हूं, तो आप पहले कॉल के बाद संदर्भ में अभी संशोधित किया है।

तो ... मुझे अपना एपीआई कैसे डिजाइन करना चाहिए? क्या मैं एक और Init विधि जोड़ता हूं जो सभी प्रश्नों को स्टाक को रीसेट करता है (लेकिन फिर मैं उन्हें कैसे शुरू करने के लिए मजबूर करता हूं?), या Reset() जोड़ें कि उन्हें अपनी लाइन के अंत में कॉल करना होगा? क्या मैं इसके बजाय [] अधिभारित करता हूं और उन्हें इसके साथ शुरू करने के लिए कहता हूं? क्या मैं कहता हूं "इसे भूल जाओ, कोई भी उन राज्य-संरक्षित कार्यों का उपयोग नहीं करता है?"

असल में, आप उस jQuery उदाहरण को सी # में कैसे लिखना पसंद करेंगे?

  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. दो अलग-अलग वस्तुओं
  6. का प्रयोग करें।
    शायद आधार है कि सभी प्रश्नों के साथ शुरू करना चाहिए, और उसके बाद हर विधि उसके बाद एक SharpQuery उद्देश्य यह है कि श्रृंखलित जा सकती है, रिटर्न के रूप में HtmlDocument का उपयोग करें। इस तरह HtmlDocument हमेशा प्रारंभिक स्थिति को बनाए रखता है, लेकिन SharpQuery ऑब्जेक्ट्स में अलग-अलग राज्य हो सकते हैं। दुर्भाग्य से इसका मतलब है कि मुझे दो बार सामानों का एक गुच्छा लागू करना है (एक बार HtmlDocument के लिए, एक बार SharpQuery ऑब्जेक्ट के लिए)।

  7. new SharpQuery(sq).Find("ul.first").Find(".foo") ...
    निर्माता प्रतियां दस्तावेज़ के लिए एक संदर्भ है, लेकिन ढेर रीसेट करता है।

+2

आईएमओ 5) सबसे अच्छा विकल्प है। यह निश्चित रूप से 'HtmlDocument' से शुरू होने वाले प्रश्नों के लिए पठनीय और सहज है, और डुप्लिकेट कार्य के लिए - उम्मीद है कि आप इसे कार्यान्वित कर सकते हैं ताकि केवल विधि हस्ताक्षर डुप्लिकेट किए जाएं, लेकिन वास्तविक तर्क नहीं। (कुछ सामान्य वर्गों को कॉल करना जो काम करता है।) मुझे विकल्प 1 भी पसंद है) और व्यक्तिगत रूप से इसे ब्रैकेट के "दुर्व्यवहार" के रूप में नहीं देखते हैं। :) –

+0

@ किर्क: '[]' आम तौर पर 'ओ (1)' ऑपरेशन इंगित करता है ... जैसे डेटा पहले ही अनुक्रमित है। इस मामले में, इसे वास्तव में एक पूर्ण खोज करना है। – mpen

+0

फिर भी, मैं अब (1) की तरफ झुका रहा हूं। असल में, मैंने इसे इस तरह कोडिंग करना शुरू कर दिया है। यह उपयोगकर्ताओं को 'फ़िंड()' के साथ सीधे कूदने से रोकता है क्योंकि संदर्भ तब तक सेट नहीं होता है जब तक वे '[] 'पर कॉल न करें। यानी, 'फिंड()' बस कुछ भी नहीं मिलेगा क्योंकि इसमें खोज करने के लिए कुछ भी नहीं है। '[]' दस्तावेज़ नोड को संदर्भ रीसेट करता है और फिर वे खोज शुरू कर सकते हैं। – mpen

उत्तर

4

मुझे लगता है कि आप यहां पर चल रहे प्रमुख ठोकरें ब्लॉक यह है कि आप प्रत्येक दस्तावेज़ के लिए केवल SharpQuery ऑब्जेक्ट को दूर करने की कोशिश कर रहे हैं। ऐसा नहीं है कि 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> 

(देखना अधिक जानकारी के लिए documentation of 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 

इस दृष्टिकोण के लाभ कई हैं। क्योंकि sq, header, allTheLinks, आदि सभी समान वर्ग हैं, आपके पास केवल प्रत्येक विधि का एक कार्यान्वयन है। फिर भी इनमें से प्रत्येक ऑब्जेक्ट एक ही दस्तावेज़ का संदर्भ देता है, इसलिए आपके पास प्रत्येक नोड की कई प्रतियां नहीं हैं, और नोड्स में परिवर्तन उस दस्तावेज़ पर प्रत्येक SharpQuery ऑब्जेक्ट में दिखाई देता है (उदा। allTheLinks.text("foo"), someOfTheLinks.text() == "foo" के बाद।)।

end को लागू करने और अन्य ढेर आधारित जोड़तोड़ भी आसान हो जाता है। प्रत्येक विधि एक नया, SharpQuery दूसरे से वस्तु फ़िल्टर्ड बनाता है के रूप में, यह है कि माता-पिता वस्तु (allTheLinksheader को, sq को header) के लिए एक संदर्भ बरकरार रखती है। तब end एक नया SharpQuery लौटने माता पिता के रूप में एक ही तत्वों से युक्त, की तरह के रूप में सरल है:

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

(या तथापि अपने वाक्य रचना बाहर हिला।)

मुझे लगता है कि इस दृष्टिकोण आप सबसे jQuery मिल जाएगा एक काफी आसान कार्यान्वयन के साथ, व्यवहार के समान।मैं निश्चित रूप से इस परियोजना पर नजर रखूंगा; यह एक महान विचार है।

+0

आह .. चालाक! मैं एक नई वस्तु वापस करने के बारे में सोच रहा था, लेकिन फिर मुझे पता नहीं लगा कि मैं ढेर कैसे बनाए रखूंगा। माता-पिता के लिए संदर्भ रखना ... इतना आसान>। < – mpen

+0

बड़ा अपडेट: http://sharp-query.googlecode.com/svn/trunk/HtmlAgilityPlus/ अब इस श्रृंखला को चेन करने के लिए उपयोग करता है। – mpen

0

मैं विकल्प 2 पर एक संस्करण की तरफ झुकता हूं। JQuery $() में एक फ़ंक्शन कॉल है। सी # में वैश्विक कार्य नहीं हैं, एक स्थिर फ़ंक्शन कॉल निकटतम है। मैं और अगर एक विधि है कि इंगित करता है कि आप एक आवरण की तरह बना रहे हैं ..

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

मैं SharpQuery छोटा वर्ग के लिए IntelliSense का मतलब है के बाद से उन पूरी बात लिखने की आवश्यकता नहीं होगी के बारे में चिंतित नहीं होगा का प्रयोग करेंगे (उनके पास रिशेर्पर है, उन्हें केवल एसक्यू टाइप करने की आवश्यकता है)।

+0

वे इसे जो कुछ भी चाहते हैं उसका नाम दे सकते हैं .. 'sq'' SharpQuery' का एक उदाहरण होगा। 'SharpQuery.Create' स्थिर विधि के रूप में काम नहीं करेगा क्योंकि आपको दस्तावेज़ को पहले लोड करना होगा ... जब तक कि आप दस्तावेज़ को स्थिर भी नहीं बनाते, लेकिन फिर आप एक समय में केवल एक दस्तावेज़ के साथ काम कर सकते हैं; एक मनमाना प्रतिबंध। – mpen