क्या विधि नाम में "Async" प्रत्यय का उपयोग इस बात पर निर्भर करता है कि 'async' संशोधक का उपयोग किया जाता है या नहीं?


106

"Async" के साथ प्रत्यय विधि के नाम के लिए सम्मेलन क्या है?

क्या "एसिंक्स" प्रत्यय को केवल एक विधि में जोड़ा जाना चाहिए जिसे asyncसंशोधक के साथ घोषित किया गया है ?

public async Task<bool> ConnectAsync()

या क्या यह पर्याप्त है कि विधि अभी वापस आती है Task<T>या Task?

public Task<bool> ConnectAsync()

4
नामकरण भाग के लिए, टीएपी डॉक्टर कहता है: टीएपी में अतुल्यकालिक विधियों में ऑपरेशन नाम के बाद एसिंक्स प्रत्यय शामिल है; उदाहरण के लिए, Get ऑपरेशन के लिए GetAsync। यदि आप किसी वर्ग के लिए एक TAP पद्धति जोड़ रहे हैं जिसमें पहले से ही Async प्रत्यय के साथ उस विधि का नाम है, तो इसके बजाय प्रत्यय TaskAsync का उपयोग करें। उदाहरण के लिए, यदि कक्षा में पहले से ही GetAsync विधि है, तो GetTaskAsync नाम का उपयोग करें।
जेम्स मैनिंग

4
ठीक है, मुझे लगता है कि मैं "async विधियों के लिए नामकरण सम्मेलन" के प्रश्न शीर्षक से उलझन में था
जेम्स मैनिंग

1
यह एक खराब तरीके से बनाया गया सवाल है। लोग मनमौजी जवाब देते हैं।
ल्यूक पुप्लेट

4
क्योंकि बहुत से लोगों ने इसे गलत समझा है और वास्तविक रूप में पूछे जाने वाले तर्क के रूप में बहस कर रहे हैं, यह सोचकर कि क्या इसका दो-भाग वाला प्रश्न है। इसका प्रमाण यह है कि लोग भ्रमित हैं।
ल्यूक पुप्लेट

2
@DavidRR इस दिन तक मुझे अभी भी भ्रम की मात्रा समझ में नहीं आई है कि यह प्रश्न स्पष्ट रूप से उत्पन्न हुआ है। यदि आपके संपादन इस भ्रम में कुछ क्रम लाते हैं कि इसने आपकी मदद की है और संभवत: दूसरों की मदद कर सकता है, तो मैं आपके संपादन का स्वागत करता हूं आपके लिए कुछ ऐसा हासिल किया है जो मैं मूल सूत्रीकरण में नहीं कर सका। यह सवाल अब इतना पुराना हो गया है कि जब मैंने यहां पूछा तो मैं अपनी मानसिकता को याद नहीं कर सकता हूं और इसलिए मूल मंशा कम महत्वपूर्ण है। ल्यूक का जवाब दर्शाता है कि सभी भ्रमित नहीं थे। मुझे यह काफी मददगार लगा।
कास्परज

जवाबों:


127

मुझे लगता है कि सच्चाई Microsoft दस्तावेज से भी अस्पष्ट है:

विजुअल स्टूडियो 2012 और .NET फ्रेमवर्क 4.5 में, asyncकीवर्ड ( Asyncविजुअल बेसिक में) के साथ किसी भी विधि को असिंक्रोनस विधि माना जाता है, और C # और विजुअल बेसिक कंप्लायंस TAP का उपयोग करके एसिंक्रोनस तरीके से विधि को लागू करने के लिए आवश्यक परिवर्तन करते हैं। एक अतुल्यकालिक विधि Taskया तो एक या एक Task<TResult>वस्तु वापस आ जाना चाहिए ।

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

यह पहले से ही ठीक नहीं है। किसी भी विधि के साथ asyncअतुल्यकालिक है और फिर यह कहते हुए कि या तो वापस लौटना चाहिए - Taskया Task<T>जो कॉल स्टैक के शीर्ष पर विधियों के लिए सही नहीं है, उदाहरण के लिए Button_Click, या async void

बेशक, आपको विचार करना होगा कि सम्मेलन का क्या मतलब है?

आप कह सकते हैं कि Asyncप्रत्यय सम्मेलन एपीआई उपयोगकर्ता के लिए संवाद करने के लिए है कि विधि प्रतीक्षित है। प्रतीक्षा योग्य विधि के लिए, इसे Taskशून्य के Task<T>लिए या मान-वापसी विधि के लिए लौटना चाहिए , जिसका अर्थ है कि केवल उत्तरार्द्ध के साथ प्रत्यय लगाया जा सकता है Async

या आप कह सकते हैं कि Asyncप्रत्यय सम्मेलन यह संवाद करने के लिए है कि विधि तुरंत वापस आ सकती है, वर्तमान धागे को त्यागकर अन्य कार्य और संभावित रूप से दौड़ का कारण बन सकती है।

यह Microsoft डॉक्टर उद्धरण कहता है:

अधिवेशन के द्वारा, आप "Async" को उन विधियों के नाम से जोड़ते हैं जिनमें Async या Async संशोधक होता है।

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

जो यह भी उल्लेख नहीं करता है कि आपके स्वयं के अतुल्यकालिक तरीकों को वापस Taskकरने के लिए Asyncप्रत्यय की आवश्यकता है , जो मुझे लगता है कि हम सभी सहमत हैं कि वे करते हैं।


तो इस सवाल का जवाब हो सकता है: दोनों। दोनों ही मामलों में, आपको कीवर्ड के Asyncतरीकों के साथ जुड़ने की जरूरत है asyncऔर वह वापसी Taskया Task<T>


मैं स्टीफन Toub से स्थिति स्पष्ट करने के लिए पूछने जा रहा हूँ।

अपडेट करें

तो मैंने किया। और यहाँ हमारे अच्छे आदमी ने क्या लिखा है:

यदि एक सार्वजनिक विधि टास्क-रिटर्निंग है और प्रकृति में अतुल्यकालिक है (एक विधि के विपरीत जिसे हमेशा पूरा करने के लिए तुल्यकालिक रूप से निष्पादित करने के लिए जाना जाता है लेकिन फिर भी किसी कारण के लिए कार्य लौटाता है), इसमें "Async" प्रत्यय होना चाहिए। वह दिशा-निर्देश है। नामकरण के साथ यहां प्राथमिक लक्ष्य कार्यक्षमता के एक उपभोक्ता को यह स्पष्ट करना है कि जिस विधि को लागू किया जा रहा है वह संभवतः अपने सभी कार्यों को समकालिक रूप से पूरा नहीं करेगा; यह निश्चित रूप से उस मामले में भी मदद करता है जहां कार्यक्षमता सिंक्रोनस और अतुल्यकालिक दोनों तरीकों से उजागर होती है जैसे कि आपको उन्हें अलग करने के लिए नाम अंतर की आवश्यकता होती है। यह विधि किस प्रकार अपने अतुल्यकालिक कार्यान्वयन को प्राप्त करती है, नामकरण के लिए अपरिवर्तित है: क्या कंपाइलर की सहायता प्राप्त करने के लिए async / wait का उपयोग किया जाता है, या क्या System.Threading.Tasks से प्रकार और विधियाँ सीधे उपयोग की जाती हैं (e) जी। TaskCompletionSource) वास्तव में कोई फर्क नहीं पड़ता, क्योंकि यह विधि के हस्ताक्षर को प्रभावित नहीं करता है, जहां तक ​​कि विधि के उपभोक्ता का संबंध है।

बेशक, हमेशा एक दिशानिर्देश के अपवाद होते हैं। नामकरण के मामले में सबसे उल्लेखनीय एक ऐसे मामले होंगे जहां एक पूरे प्रकार के raison d'etre को async-केंद्रित कार्यक्षमता प्रदान करना है, जिसमें प्रत्येक विधि पर Async होने के मामले में ओवरक्लिल होगा, जैसे कार्य पर तरीके जो स्वयं कार्य उत्पन्न करते हैं ।

शून्य-वापस लौटने वाली अतुल्यकालिक विधियों के लिए, सार्वजनिक सतह क्षेत्र में उन लोगों को रखना वांछनीय नहीं है, क्योंकि कॉलर के पास यह जानने का कोई अच्छा तरीका नहीं है कि अतुल्यकालिक काम कब पूरा हुआ है। यदि आपको सार्वजनिक रूप से एक शून्य-लौटने वाली अतुल्यकालिक विधि का पर्दाफाश करना चाहिए, हालांकि, आप संभवतः एक ऐसा नाम रखना चाहते हैं जो बताता है कि अतुल्यकालिक कार्य शुरू किया जा रहा है, और यदि आप कोई अर्थ रखते हैं तो आप यहां "Async" प्रत्यय का उपयोग कर सकते हैं। यह देखते हुए कि यह मामला कितना दुर्लभ होना चाहिए, मेरा तर्क है कि यह वास्तव में एक केस-बाय-केस का निर्णय है।

मुझे आशा है कि मदद करता है, स्टीव

स्टीफन के शुरुआती वाक्य से पर्याप्त मार्गदर्शन पर्याप्त स्पष्ट है। इसे बाहर रखा गया है async voidक्योंकि एक अतुल्यकालिक शून्य को लागू करने के सही तरीके से एक सार्वजनिक एपीआई बनाने के लिए यह असामान्य है क्योंकि यह एक सादे Taskउदाहरण को वापस करना है और संकलक को अपने जादू के लिए जाने देना है। हालांकि, यदि आप एक चाहते हैं public async void, तो अपील करने Asyncकी सलाह दी जाती है। अन्य टॉप-ऑफ़-स्टैक async voidविधियाँ जैसे कि ईवेंट हैंडलर आमतौर पर सार्वजनिक नहीं होते हैं और मायने नहीं रखते / योग्य नहीं होते हैं।

मेरे लिए, यह मुझे बताता है कि अगर मैं खुद Asyncको एक पर प्रत्यय के बारे में सोचता हुआ पाता हूं async void, तो मुझे शायद इसे बदल देना चाहिए async Taskताकि कॉल करने वाले इसका इंतजार कर सकें, फिर अपील करें Async


20
अच्छी तरह से इसकी शर्म की बात है कि हमारे पास विधि कॉल के लिए समय की जाँच नहीं है .. ओह प्रतीक्षा करें। यदि मैं मेथड गेट या गेटएस्क्यू का नाम देता हूं और कॉलिंग पक्ष से प्रतीक्षा का उपयोग नहीं करता हूं , तो संकलन बनाने में विफल हो जाएगा। तो यह सम्मेलन SILLY है और वास्तव में कई Microsoft स्टाइल दिशानिर्देशों के विरुद्ध जा रहा है, जैसे कि चीजों को टालना PersonStringया PriceDecimalउपयोग करना क्यों GetAsync- async API के API उपभोक्ताओं को इस बारे में चिंता करने की ज़रूरत नहीं है क्योंकि अनुरोध हमेशा वैसे भी पूरा होने के बाद वापस लौटता है। यह मूर्खतापूर्ण और वास्तव में मुझे परेशान कर रहा है। लेकिन इसका सिर्फ एक और सम्मेलन है कि कोई भी वास्तव में जानता है कि वहाँ क्यों।
पियोत्र कुला

2
@ppumkin: जैसा कि स्टीफन ने बताया, एक विधि आसानी से एसिंक्रोनस / वेट का उपयोग किए बिना प्रकृति में अतुल्यकालिक हो सकती है, इस प्रकार फोन करने वाले के पास नाम के अलावा कोई संकेत नहीं है कि कार्यक्षमता अतुल्यकालिक चलती है या नहीं।
हनोबो सेप

6
@ppumkin: डिफ़ॉल्ट रूप से, एक संकलित विधि का इंतजार करने में असफल, एक संकलन-समय की चेतावनी के परिणामस्वरूप; बिल्ड एरर नहीं।
डस्टिन क्लीवलैंड

7
मुझे यह सम्मेलन मूर्खतापूर्ण लगता है। तीन स्वचालित संकेत हैं जो एक विधि async है: 1. वापसी प्रकार टास्क है। 2. कोड पूरा होने से एक अचंभित संकेत प्रस्तुत होता है। IDE आपको हरे रंग में रेखांकित करके और एक संकलक चेतावनी प्रस्तुत करके चेतावनी देगा। इसलिए मैं पूरी तरह से @ppumkin से सहमत हूं। Async-suffix उतना ही मूर्खतापूर्ण है जैसे कि आपने कोई संपत्ति लिखी हो जैसे: Public Lazy <Customer> CustomerLazy। ऐसा कौन करेगा ??
मार्को

2
@ मर्को मैंने गीथहब पर इस विचार को उठाया, सोचा कि यह सबसे अच्छी जगह है, लेकिन इसके साथ सगाई नहीं है मुझे लगा कि मुझे मिलेगा: github.com/dotnet/core/issues/1464
ल्यूक पुप्लेट

68

मैं बहुत सारी एपीआई-सेवाओं और अन्य अनुप्रयोगों का निर्माण करता हूं जो अन्य प्रणालियों को कॉल करते हैं जहां मेरा अधिकांश कोड अतुल्यकालिक चल रहा है।

मेरे अपने अंगूठे का नियम मैं निम्नलिखित है:

यदि दोनों गैर-एसिंक्स और एसिंक्रोस विधि है जो एक ही चीज को वापस करते हैं तो मैं एसिंक्स के साथ एसिंक्स एक को प्रत्यय देता हूं। नहीं तो नहीं।

उदाहरण:

केवल एक विधि:

public async Task<User> GetUser() { [...] }

दो हस्ताक्षर के साथ एक ही विधि:

public User GetUser() { [...] }

public async Task<User> GetUserAsync() { [...] }

यह समझ में आता है क्योंकि यह वही डेटा है जो वापस आ गया है लेकिन केवल एक चीज जो अलग है वह डेटा वापस करने का तरीका है , न कि डेटा।

मुझे यह भी लगता है कि यह नामकरण परंपराएं एस्किंट विधियों को पेश करने की आवश्यकता के कारण मौजूद हैं और अभी भी पीछे की संगतता बनाए रखती हैं।

मेरा तर्क है कि नए कोड में एसिंक्स प्रत्यय का उपयोग नहीं होना चाहिए। यह स्ट्रिंग में वापसी के प्रकार के रूप में स्पष्ट है, या इंट पहले जैसा उल्लेख किया गया है।


8
मैं सहमत हूँ, विशेष रूप से कि आमतौर पर आपको 'सभी तरह से async' जाने की जरूरत होती है, जिस स्थिति में प्रत्यय निरर्थक है - इसे 90% कोड में जोड़ने की बात क्या है?)
बार्टोज़

3
यह सबसे अच्छा उपाय है। इसे देखे बिना, मैं अपने एपीआई में उसी तरह कर रहा हूं।
मार्को

2
यह "Async" सभी प्रकार के async अनुप्रयोग के प्रत्यय से बेहतर है
Mariusz Jamro

इस तकनीक के साथ समस्या यह है कि यदि आप बाद में एक नॉन-एसिक्स वर्जन बनाते हैं, तो आप अपने अन्यथा पसंदीदा "गेटउज़र ()" नाम का उपयोग नहीं कर सकते।
डेविड

3
यह जाने के लिए व्यावहारिक तरीका है। Async को संशोधित करने वाली प्रत्येक विधि में Async संशोधक को लागू करना सिर्फ हंगेरियन नोटेशन 2019 है। @David यदि आप बाद में एक गैर- async संस्करण जोड़ते हैं, तो विधियों का नाम बदलें और नामकरण सम्मेलन का अनुसरण करें या बस ऐसा न करें।
स्क्रीम्सली

25

"Async" के साथ विधि नाम प्रत्यय के लिए सम्मेलन क्या है।

टास्क आधारित अतुल्यकालिक पैटर्न (TAP) तय कर कि तरीकों हमेशा एक लौटना चाहिए Task<T>(या Task) और एक साथ नामित किया Async प्रत्यय; यह के उपयोग से अलग है async। दोनों Task<bool> Connect()और संकलन होगा और ठीक चलाते हैं, लेकिन नल नामकरण सम्मेलन निम्नलिखित नहीं किया जाएगा।asyncTask<bool> Connect()

क्या विधि में asyncसंशोधक होना चाहिए , या यह पर्याप्त है कि यह बस कार्य लौटाता है?

यदि विधि का शरीर (वापसी प्रकार या नाम की परवाह किए बिना) शामिल है await, तो आपको इसका उपयोग करना चाहिएasync ; और कंपाइलर आपको बताएगा कि "द वेट 'ऑपरेटर केवल एक एसिंक्स पद्धति के भीतर इस्तेमाल किया जा सकता है। ..."। लौटने Task<T>या Taskउपयोग करने से बचने के लिए "पर्याप्त" नहीं है async। देखें (सी # संदर्भ) async जानकारी के लिए।

यानी इनमें से कौन से हस्ताक्षर सही हैं:

दोनों और टीएपी सम्मेलनों का ठीक से पालन करते हैं। आप हमेशा कीवर्ड का उपयोग कर सकते हैं, लेकिन आपको एक कंपाइलर चेतावनी मिलेगी "इस एस्किंस मेथड में 'वेट' ऑपरेटरों की कमी है और यह सिंक्रोनाइज़ रन करेगा।" "यदि शरीर उपयोग नहीं करता है ।asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()asyncawait


1
वह इस बात का उल्लेख कर रहा है कि आप "Async" को विधि नाम से जोड़ते हैं या नहीं, चाहे आप asyncकीवर्ड का उपयोग करें या नहीं ।
सर्व

1
@ कीवर्ड asyncका उपयोग करना या कीवर्ड का उपयोग न करना सवाल का दूसरा हिस्सा है।
कोर्क

2
@ सर्वे यह एक दो भाग का प्रश्न है। पहला भाग, जैसा कि आपने कहा था कि "Async" को विधि नाम में जोड़ा जाना है या नहीं। दूसरा भाग asyncसंशोधक का उपयोग करना है या नहीं । OPs उदाहरण भी देखें, public async Task<bool> ConnectAsync()( asyncसंशोधक के साथ ) बनाम public Task<bool> ConnectAsync()( asyncसंशोधक के बिना )। विधि नाम में ही दोनों मामलों में प्रत्यय "Async" है।
कोरक

2
यह है नहीं एक दो भाग सवाल। सवाल यह है कि, "Async" को उन विधियों के नामों से जोड़ा जाना चाहिए जो वापस आती हैं Taskया जो विधियाँ हैं async Task
कास्परज

3
@ एलजॉन: आपको सवाल सुधारना चाहिए; "बनाम" कोड स्निपेट यह सवाल स्पष्ट करता है (इसकी संपूर्णता में) async के बारे में है क्योंकि यह एकमात्र अंतर है।
Ðаn

11

या यह पर्याप्त है कि यह सिर्फ टास्क लौटाता है?

उस। asyncकीवर्ड यहाँ असली मुद्दा नहीं है। यदि आप asyncकीवर्ड का उपयोग किए बिना एसिंक्रोनसी को लागू करते हैं, तो यह विधि सामान्य अर्थ में "Async" है।


7

के बाद से Taskऔर Task<T>दोनों awaitable प्रकार के होते हैं, वे प्रतिनिधित्व करते हैं कुछ अतुल्यकालिक ऑपरेशन का । या कम से कम उन्हें प्रतिनिधित्व करना चाहिए।

आपको Asyncएक विधि में प्रत्यय जोड़ना चाहिए , जो कुछ मामलों में (जरूरी नहीं कि सभी), एक मान वापस नहीं करता है, बल्कि एक चालू ऑपरेशन के आसपास एक आवरण देता है। वह आवरण आमतौर पर एक है Task, लेकिन विंडोज आरटी पर यह हो सकता है IAsyncInfo। अपनी आंत की भावना का पालन करें और याद रखें कि यदि आपके कोड का उपयोगकर्ता Asyncफ़ंक्शन देखता है , तो उसे पता चलेगा कि उस पद्धति के परिणाम से उस पद्धति का आह्वान डिकोड किया गया है और उन्हें उसी के अनुसार कार्य करने की आवश्यकता है।

ध्यान दें कि इस तरह के तरीके हैं Task.Delayऔर Task.WhenAllजो वापस आते हैं Taskऔर अभी तक Asyncप्रत्यय नहीं है ।

यह भी ध्यान दें कि ऐसे async voidतरीके हैं जो आग का प्रतिनिधित्व करते हैं और अतुल्यकालिक विधि को भूल जाते हैं और आपको बेहतर तरीके से पता होना चाहिए कि विधि इस तरह से बनाई गई है।


6

मैं यह तर्क दूंगा कि यदि किसी कार्य को asyncसंशोधक के साथ घोषित किया जाता है या नहीं, तो यह असंस-प्रत्यय का उपयोग करना चाहिए ।

इसके पीछे कारण यह है कि इंटरफ़ेस में नाम घोषित किया गया है। इंटरफ़ेस रिटर्न प्रकार की घोषणा करता है जो कि ए Task। फिर उस इंटरफ़ेस के दो कार्यान्वयन हैं, एक कार्यान्वयन इसे asyncसंशोधक का उपयोग करके लागू करता है, दूसरा नहीं करता है।

public interface IFoo
{
    Task FooAsync();
}

public class FooA : IFoo
{
    public Task FooAsync() { /* ... */ }
}

public class FooB : IFoo
{
    public async Task FooAsync() { /* ... */ }
}

ये बिल्कुल सही है। हम हमेशा सभी जगह इंटरफेस का उपयोग करते हैं, और इंटरफेस को एसिंक्रोनस घोषित नहीं किया जा सकता है। तो Async प्रत्यय का उपयोग करने पर आधिकारिक गाइड मुझे पूरी तरह से बकवास लगते हैं। मुझे लगता है कि async कीवर्ड सिर्फ एक कार्यान्वयन विवरण है, विधि के इंटर्नल का हिस्सा है, और इसके नाम या जो कुछ भी बाहरी को प्रभावित नहीं करना चाहिए।
अल केप्प

5

में async और साथ अतुल्यकालिक प्रोग्रामिंग इंतजार (सी #) , माइक्रोसॉफ्ट निम्नलिखित मार्गदर्शन प्रदान करता है:

नामकरण परंपरा

अधिवेशन द्वारा, आप "Async" को उन विधियों के नाम से जोड़ते हैं जिनमें एक Async संशोधक है।

आप उस सम्मलेन को अनदेखा कर सकते हैं जहाँ कोई घटना, आधार वर्ग या इंटरफ़ेस अनुबंध एक अलग नाम सुझाता है। उदाहरण के लिए, आपको सामान्य ईवेंट हैंडलर्स का नाम नहीं बदलना चाहिए, जैसे कि Button1_Click

मुझे यह मार्गदर्शन अधूरा और असंतोषजनक लगता है। क्या इसका मतलब यह है कि asyncसंशोधक की अनुपस्थिति में , इस विधि को Connectइसके बजाय नाम दिया जाना चाहिए ConnectAsync?

public Task<bool> ConnectAsync()
{
    return ConnectAsyncInternal();
}

मुझे ऐसा नहीं लगता। जैसा कि @Servy द्वारा संक्षिप्त जवाब और @Luke Puplett द्वारा अधिक विस्तृत जवाब में संकेत दिया गया है , मेरा मानना ​​है कि यह उचित है और वास्तव में उम्मीद है कि इस विधि का नाम होना चाहिए (क्योंकि यह एक प्रतीक्षा योग्य रिटर्न देता है)। इस के आगे समर्थन में, @ जॉन स्कीट में इस सवाल का जवाब एक और सवाल करने के लिए संलग्न कर देता है की उपस्थिति की परवाह किए बिना विधि नाम के संशोधक।ConnectAsyncAsyncasync

अंत में, पर एक और सवाल , पर विचार इस टिप्पणी से @Damien_The_Unbeliever :

async/awaitआपके तरीकों का कार्यान्वयन विवरण हैं । यह मायने नहीं रखता है कि क्या आपका तरीका घोषित किया गया है async Task Method()या बस Task Method(), जहां तक ​​आपके कॉल करने वालों का संबंध है। (वास्तव में, आप बाद में इन दोनों के बीच परिवर्तन करने के लिए स्वतंत्र हैं, जब तक कि इसे ब्रेकिंग परिवर्तन नहीं माना जाता।)

उस से, मैं अनुमान लगाता हूं कि यह उस पद्धति की अतुल्यकालिक प्रकृति है जो यह निर्धारित करती है कि इसका नाम कैसे रखा जाना चाहिए। विधि के उपयोगकर्ता को यह भी पता नहीं चलेगा कि asyncइसके कार्यान्वयन में संशोधक का उपयोग किया गया है (C # स्रोत कोड या CIL के बिना)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.