"किसी घटना के निकाल दिए जाने तक कोड प्रवाह कैसे अवरुद्ध करें?"
आपका दृष्टिकोण गलत है। इवेंट-चालित का मतलब किसी इवेंट के लिए ब्लॉक करना और इंतजार करना नहीं है। आप कभी भी प्रतीक्षा न करें, कम से कम आप हमेशा इससे बचने की भरसक कोशिश करते हैं। वेटिंग संसाधनों को बर्बाद कर रहा है, थ्रेड्स को अवरुद्ध कर रहा है और शायद एक गतिरोध या ज़ोंबी थ्रेड के जोखिम का परिचय दे रहा है (यदि रिलीज का संकेत कभी नहीं उठाया जाता है)।
यह स्पष्ट होना चाहिए कि किसी घटना की प्रतीक्षा करने के लिए एक धागा को अवरुद्ध करना एक विरोधी पैटर्न है क्योंकि यह एक घटना के विचार का खंडन करता है।
आपके पास आम तौर पर दो (आधुनिक) विकल्प होते हैं: एक अतुल्यकालिक एपीआई या एक घटना-संचालित एपीआई को लागू करें। चूंकि आप अपने एपीआई को एसिंक्रोनस लागू नहीं करना चाहते हैं, इसलिए आपको इवेंट-संचालित एपीआई के साथ छोड़ दिया जाता है।
ईवेंट-चालित API की कुंजी यह है कि कॉल करने वाले को परिणाम के लिए समकालिक रूप से प्रतीक्षा करने या परिणाम के लिए सर्वेक्षण करने के लिए मजबूर करने के बजाय, आप कॉलर को जारी रखने दें और उसे एक अधिसूचना भेजें, जब परिणाम तैयार हो जाता है या ऑपरेशन पूरा हो जाता है। इस बीच, कॉल करने वाला अन्य कार्यों को निष्पादित करना जारी रख सकता है।
जब थ्रेडिंग के नजरिए से समस्या को देखते हैं, तो ईवेंट-चालित एपीआई कॉलिंग थ्रेड को अनुमति देता है जैसे, UI थ्रेड, जो बटन के ईवेंट हैंडलर को निष्पादित करता है, यूआई से संबंधित अन्य संचालन जैसे कि यूआई तत्वों को रेंडर करने के लिए जारी रखने के लिए स्वतंत्र होना चाहिए। या माउस आंदोलन और प्रमुख प्रेस की तरह उपयोगकर्ता इनपुट से निपटने। ईवेंट-चालित एपीआई का एक अतुल्यकालिक एपीआई की तरह ही प्रभाव या लक्ष्य होता है, हालांकि यह बहुत कम सुविधाजनक है।
चूंकि आपने वास्तव में क्या करने की कोशिश कर रहे हैं, इस पर पर्याप्त विवरण नहीं दिया है कि वास्तव में क्या कर रहे Utility.PickPoint()
हैं और कार्य का परिणाम क्या है या उपयोगकर्ता को `ग्रिड पर क्लिक करना है, तो मैं आपको एक बेहतर समाधान प्रदान नहीं कर सकता। । मैं सिर्फ अपनी आवश्यकता को लागू करने के सामान्य तरीके की पेशकश कर सकता हूं।
आपके प्रवाह या लक्ष्य को स्पष्ट रूप से कम से कम दो चरणों में विभाजित किया गया है ताकि इसे संचालन का क्रम बनाया जा सके:
- उपयोगकर्ता द्वारा बटन क्लिक करने पर ऑपरेशन 1 निष्पादित करें
- जब उपयोगकर्ता क्लिक करता है, तब ऑपरेशन 2 (जारी / पूरा ऑपरेशन 1) जारी रखें
Grid
कम से कम दो बाधाओं के साथ:
- वैकल्पिक: एपीआई क्लाइंट को इसे दोहराने की अनुमति देने से पहले अनुक्रम पूरा होना चाहिए। एक अनुक्रम पूरा हो गया है जब ऑपरेशन 2 पूरा होने के लिए चला गया है।
- ऑपरेशन 1 हमेशा ऑपरेशन से पहले निष्पादित किया जाता है। ऑपरेशन 1 अनुक्रम शुरू करता है।
- ऑपरेशन 2 को निष्पादित करने के लिए एपीआई क्लाइंट को अनुमति देने से पहले ऑपरेशन 1 को पूरा करना होगा
गैर-अवरोधक इंटरैक्शन की अनुमति देने के लिए एपीआई के क्लाइंट के लिए दो सूचनाओं (घटनाओं) की आवश्यकता होती है:
- ऑपरेशन 1 पूरा (या आवश्यक बातचीत)
- ऑपरेशन 2 (या लक्ष्य) पूरा हुआ
आपको दो सार्वजनिक तरीकों और दो सार्वजनिक घटनाओं को उजागर करके अपने एपीआई को इस व्यवहार और बाधाओं को लागू करने देना चाहिए।
चूंकि यह कार्यान्वयन केवल एपीआई (एकल-समवर्ती) कॉल की अनुमति देता है एपीआई के लिए यह IsBusy
एक रनिंग अनुक्रम को इंगित करने के लिए एक संपत्ति को उजागर करने की भी सिफारिश की जाती है । यह एक नया अनुक्रम शुरू करने से पहले वर्तमान स्थिति को मतदान करने की अनुमति देता है, हालांकि बाद की कॉल को निष्पादित करने के लिए पूर्ण घटना की प्रतीक्षा करने की सिफारिश की जाती है।
यूटिलिटी एपीआई को लागू / रिफलेक्टर
Utility.cs
class Utility
{
public event EventHandler InitializePickPointCompleted;
public event EventHandler<PickPointCompletedEventArgs> PickPointCompleted;
public bool IsBusy { get; set; }
private bool IsPickPointInitialized { get; set; }
// The prefix 'Begin' signals the caller or client of the API,
// that he also has to end the sequence explicitly
public void BeginPickPoint(param)
{
// Implement constraint 1
if (this.IsBusy)
{
// Alternatively just return or use Try-do pattern
throw new InvalidOperationException("BeginPickPoint is already executing. Call EndPickPoint before starting another sequence.");
}
// Set the flag that a current sequence is in progress
this.IsBusy = true;
// Execute operation until caller interaction is required.
// Execute in background thread to allow API caller to proceed with execution.
Task.Run(() => StartOperationNonBlocking(param));
}
public void EndPickPoint(param)
{
// Implement constraint 2 and 3
if (!this.IsPickPointInitialized)
{
// Alternatively just return or use Try-do pattern
throw new InvalidOperationException("BeginPickPoint must have completed execution before calling EndPickPoint.");
}
// Execute operation until caller interaction is required.
// Execute in background thread to allow API caller to proceed with execution.
Task.Run(() => CompleteOperationNonBlocking(param));
}
private void StartOperationNonBlocking(param)
{
... // Do something
// Flag the completion of the first step of the sequence (to guarantee constraint 2)
this.IsPickPointInitialized = true;
// Request caller interaction to kick off EndPickPoint() execution
OnInitializePickPointCompleted();
}
private void CompleteOperationNonBlocking(param)
{
// Execute goal and get the result of the completed task
Point result = ExecuteGoal();
// Reset API sequence (allow next client invocation)
this.IsBusy = false;
this.IsPickPointInitialized = false;
// Notify caller that execution has completed and the result is available
OnPickPointCompleted(result);
}
private void OnInitializePickPointCompleted()
{
// Set the result of the task
this.InitializePickPointCompleted?.Invoke(this, EventArgs.Empty);
}
private void OnPickPointCompleted(Point result)
{
// Set the result of the task
this.PickPointCompleted?.Invoke(this, new PickPointCompletedEventArgs(result));
}
}
PickPointCompletedEventArgs.cs
class PickPointCompletedEventArgs : AsyncCompletedEventArgs
{
public Point Result { get; }
public PickPointCompletedEventArgs(Point result)
{
this.Result = result;
}
}
एपीआई का उपयोग करें
MainWindow.xaml.cs
partial class MainWindow : Window
{
private Utility Api { get; set; }
public MainWindow()
{
InitializeComponent();
this.Api = new Utility();
}
private void StartPickPoint_OnButtonClick(object sender, RoutedEventArgs e)
{
this.Api.InitializePickPointCompleted += RequestUserInput_OnInitializePickPointCompleted;
// Invoke API and continue to do something until the first step has completed.
// This is possible because the API will execute the operation on a background thread.
this.Api.BeginPickPoint();
}
private void RequestUserInput_OnInitializePickPointCompleted(object sender, EventArgs e)
{
// Cleanup
this.Api.InitializePickPointCompleted -= RequestUserInput_OnInitializePickPointCompleted;
// Communicate to the UI user that you are waiting for him to click on the screen
// e.g. by showing a Popup, dimming the screen or showing a dialog.
// Once the input is received the input event handler will invoke the API to complete the goal
MessageBox.Show("Please click the screen");
}
private void FinishPickPoint_OnGridMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
this.Api.PickPointCompleted += ShowPoint_OnPickPointCompleted;
// Invoke API to complete the goal
// and continue to do something until the last step has completed
this.Api.EndPickPoint();
}
private void ShowPoint_OnPickPointCompleted(object sender, PickPointCompletedEventArgs e)
{
// Cleanup
this.Api.PickPointCompleted -= ShowPoint_OnPickPointCompleted;
// Get the result from the PickPointCompletedEventArgs instance
Point point = e.Result;
// Handle the result
MessageBox.Show(point.ToString());
}
}
MainWindow.xaml
<Window>
<Grid MouseLeftButtonUp="FinishPickPoint_OnGridMouseLeftButtonUp">
<Button Click="StartPickPoint_OnButtonClick" />
</Grid>
</Window>
टिप्पणियों
पृष्ठभूमि थ्रेड पर उठाए गए इवेंट उसी थ्रेड पर अपने हैंडलर निष्पादित करेंगे। DispatcherObject
एक हैंडलर से एक यूआई तत्व की तरह एक्सेस करना , जिसे एक बैकग्राउंड थ्रेड पर निष्पादित किया जाता है, क्रिटिकल ऑपरेशन को या Dispatcher
तो उपयोग करने के लिए Dispatcher.Invoke
या Dispatcher.InvokeAsync
क्रॉस-थ्रेड अपवादों से बचने के लिए आवश्यक है। डिस्पैचर आत्मीयता या थ्रेड एफिनिटी नामक इस घटना के बारे में अधिक जानने के
लिए टिप्पणियों को पढ़ें DispatcherObject
।
एपीआई के सुविधाजनक उपयोग के लिए मैं सभी घटनाओं को कॉलर के मूल संदर्भ में या तो कैप्चर करने और कॉल करने वाले का SynchronizationContext
उपयोग करके AsyncOperation
या (या AsyncOperationManager
) का उपयोग करने का सुझाव देता हूं ।
उपर्युक्त उदाहरण को आसानी से रद्द करके (उदाहरण के लिए) एक Cancel()
विधि जैसे, PickPointCancel()
और प्रगति रिपोर्टिंग (अधिमानतः उपयोग करके Progress<T>
) प्रदान करके बढ़ाया जा सकता है ।
कुछ विचार - आपकी टिप्पणियों का उत्तर देते हैं
क्योंकि आप "बेहतर" अवरोधक समाधान खोजने के लिए मुझसे संपर्क कर रहे थे, इसलिए मुझे सांत्वना अनुप्रयोगों का उदाहरण दिया, मैंने आपको समझा दिया, कि आपकी धारणा या दृष्टिकोण पूरी तरह से गलत है।
"कोड की इन दो पंक्तियों के साथ एक कंसोल एप्लिकेशन पर विचार करें।
var str = Console.ReadLine();
Console.WriteLine(str);
जब आप डिबग मोड में एप्लिकेशन निष्पादित करते हैं तो क्या होता है। यह कोड की पहली पंक्ति पर रुक जाएगा और आपको कंसोल यूआई में एक मान दर्ज करने के लिए मजबूर करेगा और उसके बाद आप कुछ दर्ज करें और Enter दबाएं, यह अगली पंक्ति को निष्पादित करेगा और वास्तव में आपके द्वारा दर्ज किए गए प्रिंट करें। मैं बिल्कुल उसी व्यवहार के बारे में सोच रहा था लेकिन डब्ल्यूपीएफ एप्लिकेशन में। ”
एक कंसोल एप्लिकेशन कुछ पूरी तरह से अलग है। थ्रेडिंग कॉन्सेप्ट थोड़ा अलग है। कंसोल अनुप्रयोगों में GUI नहीं है। बस इनपुट / आउटपुट / एरर स्ट्रीम। आप एक कंसोल एप्लीकेशन के आर्किटेक्चर की तुलना जीयूआई एप्लीकेशन से नहीं कर सकते। यह काम नहीं करेगा। आपको वास्तव में इसे समझना और स्वीकार करना चाहिए।
इसके अलावा लगता है धोखा नहीं है । क्या आप जानते हैं कि अंदर क्या हो रहा हैConsole.ReadLine
? इसे कैसे लागू किया जाता है ? क्या यह मुख्य धागे को अवरुद्ध कर रहा है और समानांतर में यह इनपुट पढ़ता है? या यह सिर्फ मतदान है?
यहाँ इसका मूल कार्यान्वयन है Console.ReadLine
:
public virtual String ReadLine()
{
StringBuilder sb = new StringBuilder();
while (true)
{
int ch = Read();
if (ch == -1)
break;
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' && Peek() == '\n')
Read();
return sb.ToString();
}
sb.Append((char)ch);
}
if (sb.Length > 0)
return sb.ToString();
return null;
}
जैसा कि आप देख सकते हैं कि यह एक सरल तुल्यकालिक ऑपरेशन है। यह एक "अनंत" लूप में उपयोगकर्ता इनपुट के लिए मतदान करता है। कोई जादू ब्लॉक और जारी नहीं।
WPF एक रेंडरिंग थ्रेड और UI थ्रेड के आसपास बना है। उन थ्रेड हमेशा ओएस के साथ संवाद करने के लिए कताई करते रहते हैं जैसे उपयोगकर्ता इनपुट को संभालना - एप्लिकेशन को उत्तरदायी रखना । आप कभी भी इस थ्रेड को रोकना / ब्लॉक नहीं करना चाहते क्योंकि यह आवश्यक पृष्ठभूमि के काम को करने से फ्रेमवर्क को रोक देगा, जैसे कि माउस ईवेंट का जवाब देना - आप नहीं चाहते कि माउस फ्रीज़ हो:
प्रतीक्षा करना = थ्रेड ब्लॉक करना = अप्रतिष्ठित होना = बुरा यूएक्स = परेशान उपयोगकर्ता / ग्राहक = कार्यालय में परेशानी।
कभी-कभी, एप्लिकेशन प्रवाह को इनपुट या एक रूटीन को पूरा करने के लिए इंतजार करना पड़ता है। लेकिन हम मुख्य सूत्र को अवरुद्ध नहीं करना चाहते हैं।
इसलिए लोगों ने जटिल अतुल्यकालिक प्रोग्रामिंग मॉडल का आविष्कार किया, ताकि मुख्य धागे को अवरुद्ध किए बिना प्रतीक्षा करने और डेवलपर को जटिल और गलत तरीके से मल्टीथ्रेडिंग कोड लिखने के लिए मजबूर किया जा सके।
प्रत्येक आधुनिक एप्लिकेशन फ्रेमवर्क सरल और कुशल कोड के विकास की अनुमति देने के लिए अतुल्यकालिक संचालन या एक अतुल्यकालिक प्रोग्रामिंग मॉडल प्रदान करता है।
यह तथ्य कि आप अतुल्यकालिक प्रोग्रामिंग मॉडल का विरोध करने के लिए कड़ी मेहनत कर रहे हैं, मेरे लिए कुछ समझ की कमी दर्शाता है। हर आधुनिक डेवलपर एक तुल्यकालिक एक पर एक अतुल्यकालिक एपीआई पसंद करता है। कोई भी गंभीर डेवलपर await
कीवर्ड का उपयोग करने या उसकी विधि घोषित करने की परवाह नहीं करता है async
। कोई भी नहीं। आप पहले I मुठभेड़ हैं जो अतुल्यकालिक एपीआई के बारे में शिकायत करते हैं और जो उन्हें उपयोग करने के लिए असुविधाजनक पाते हैं।
अगर मैं आपके फ्रेमवर्क की जांच करूंगा, जो UI संबंधित समस्याओं को हल करने या UI से संबंधित कार्यों को आसान बनाने का लक्ष्य रखता है, तो मैं उम्मीद करूंगा कि यह अतुल्यकालिक हो - सभी तरह से।
यूआई संबंधित एपीआई जो अतुल्यकालिक नहीं है, बेकार है, क्योंकि यह मेरी प्रोग्रामिंग शैली को जटिल करेगा, इसलिए मेरा कोड जो इसलिए अधिक त्रुटि-प्रवण और बनाए रखना मुश्किल हो जाता है।
एक अलग परिप्रेक्ष्य: जब आप स्वीकार करते हैं कि प्रतीक्षा UI थ्रेड को ब्लॉक करता है, तो बहुत बुरा और अवांछनीय उपयोगकर्ता अनुभव बना रहा है क्योंकि UI समाप्त होने तक फ्रीज हो जाएगा, अब जब आपको पता चलता है, तो आप एपीआई या प्लगइन मॉडल की पेशकश क्यों करेंगे एक डेवलपर को यह करने के लिए प्रोत्साहित करता है - प्रतीक्षा को लागू करें?
आप नहीं जानते कि तीसरा पक्ष प्लगइन क्या करेगा और एक रूटीन पूरा होने तक कितना समय लगेगा। यह बस एक बुरा एपीआई डिजाइन है। जब आपका एपीआई UI थ्रेड पर काम करता है तो आपके एपीआई के कॉलर को गैर-अवरोधक कॉल करने में सक्षम होना चाहिए।
यदि आप एकमात्र सस्ते या सुशोभित समाधान से इनकार करते हैं, तो मेरे उदाहरण में दिखाए गए घटना-संचालित दृष्टिकोण का उपयोग करें।
यह वही करता है जो आप चाहते हैं: एक दिनचर्या शुरू करें - उपयोगकर्ता इनपुट की प्रतीक्षा करें - निष्पादन जारी रखें - लक्ष्य पूरा करें।
मैंने वास्तव में यह समझाने की कई बार कोशिश की कि प्रतीक्षा / अवरोधन एक खराब एप्लिकेशन डिज़ाइन क्यों है। फिर, आप एक कंसोल UI की तुलना एक समृद्ध ग्राफिकल यूआई से नहीं कर सकते हैं, जहां अकेले इनपुट स्ट्रीम को सुनने की तुलना में अकेले इनपुट हैंडलिंग एक भीड़ अधिक जटिल है। मुझे वास्तव में आपके अनुभव स्तर का पता नहीं है और आपने कहाँ शुरू किया है, लेकिन आपको एसिंक्रोनस प्रोग्रामिंग मॉडल को गले लगाना शुरू करना चाहिए। मैं इसका कारण नहीं जानता कि आप इससे बचने की कोशिश क्यों करते हैं। लेकिन यह बिल्कुल भी समझदारी नहीं है।
आज अतुल्यकालिक प्रोग्रामिंग मॉडल हर जगह, हर प्लेटफॉर्म, कंपाइलर, हर पर्यावरण, ब्राउज़र, सर्वर, डेस्कटॉप, डेटाबेस पर - हर जगह लागू होते हैं। ईवेंट-चालित मॉडल एक ही लक्ष्य को प्राप्त करने की अनुमति देता है, लेकिन पृष्ठभूमि के थ्रेड्स पर भरोसा करते हुए (घटनाओं के बारे में जानने के लिए डॉक्स (जब डॉक्स हैं) पढ़ें) का उपयोग करना (सब्सक्राइब करना / अनसब्सक्राइब करना) कम सुविधाजनक है। ईवेंट-चालित पुराने जमाने का है और इसका उपयोग केवल तब किया जाना चाहिए जब अतुल्यकालिक लाइब्रेरी उपलब्ध न हों या लागू न हों।
एक साइड-नोट के रूप में: .NET फ्रेमवर्क (.NET मानक) TaskCompletionSource
एक मौजूदा समतुल्य एपीआई को एक अतुल्यकालिक एपीआई में बदलने के लिए एक सरल तरीका प्रदान करने के लिए (अन्य उद्देश्यों के बीच ) प्रदान करता है।
"मैंने ऑटोडेस्क रेविट में सटीक व्यवहार देखा है।"
व्यवहार (जो आप अनुभव करते हैं या निरीक्षण करते हैं) इस अनुभव को लागू करने के तरीके से बहुत अलग है। दो अलग बातें। आपका ऑटोडेस्क अतुल्यकालिक पुस्तकालयों या भाषा सुविधाओं या कुछ अन्य थ्रेडिंग तंत्र का उपयोग करने की संभावना है। और यह संदर्भ से संबंधित भी है। जब आपके दिमाग में जो विधि होती है, वह एक बैकग्राउंड थ्रेड पर निष्पादित होती है, तब डेवलपर इस थ्रेड को ब्लॉक करने का विकल्प चुन सकता है। उसके पास ऐसा करने के लिए या तो एक बहुत अच्छा कारण है या सिर्फ एक खराब डिजाइन विकल्प है। आप पूरी तरह से गलत रास्ते पर हैं;) अवरुद्ध करना अच्छा नहीं है।
(क्या ऑटोडेस्क सोर्स कोड ओपन सोर्स है? या आप कैसे जानते हैं कि इसे कैसे लागू किया जाता है?)
मैं आपको नाराज नहीं करना चाहता, कृपया मेरी बात पर विश्वास करें। लेकिन कृपया अपने एपीआई अतुल्यकालिक को लागू करने के लिए पुनर्विचार करें। यह केवल आपके सिर में है कि डेवलपर्स को एसिंक्स / वेट का उपयोग करना पसंद नहीं है। आपको स्पष्ट रूप से गलत मानसिकता मिली। और उस कंसोल एप्लिकेशन तर्क के बारे में भूल जाओ - यह बकवास है;)
यूआई संबंधित एपीआई चाहिए का उपयोग async / इंतजार जब भी संभव हो। अन्यथा, आप अपने एपीआई के ग्राहक को गैर-अवरोधक कोड लिखने के लिए सभी काम छोड़ देते हैं। आप मुझे हर कॉल को अपने बैकग्राउंड थ्रेड में एपीआई में लपेटने के लिए मजबूर करेंगे। या कम आरामदायक ईवेंट हैंडलिंग का उपयोग करने के लिए। मेरा विश्वास करो - हर डेवलपर async
इवेंट हैंडलिंग करने की तुलना में अपने सदस्यों को सजाता है । हर बार जब आप घटनाओं का उपयोग करते हैं तो आप एक संभावित मेमोरी रिसाव का जोखिम उठा सकते हैं - कुछ परिस्थितियों पर निर्भर करता है, लेकिन प्रोग्रामिंग लापरवाह होने पर जोखिम वास्तविक और दुर्लभ नहीं है।
मैं वास्तव में आशा करता हूं कि आप समझ गए होंगे कि ब्लॉकिंग खराब क्यों है। मैं वास्तव में आशा करता हूं कि आप एक आधुनिक अतुल्यकालिक एपीआई लिखने के लिए async / प्रतीक्षा का उपयोग करने का निर्णय लेते हैं। फिर भी, मैंने आपको घटनाओं का उपयोग करके गैर-अवरोधक प्रतीक्षा करने के लिए एक बहुत ही सामान्य तरीका दिखाया, हालांकि मैं आपसे async / प्रतीक्षा का उपयोग करने का आग्रह करता हूं।
"एपीआई प्रोग्रामर को UI और आदि तक पहुंचने की अनुमति देगा। मान लीजिए कि प्रोग्रामर एक ऐड-इन विकसित करना चाहता है, जब एक बटन पर क्लिक किया जाता है, तो अंतिम उपयोगकर्ता को यूआई में एक बिंदु चुनने के लिए कहा जाता है"
यदि आप प्लगइन को यूआई तत्वों तक सीधी पहुंच की अनुमति नहीं देना चाहते हैं, तो आपको घटनाओं को सौंपने या सार वाले ऑब्जेक्ट के माध्यम से आंतरिक घटकों को उजागर करने के लिए एक इंटरफ़ेस प्रदान करना चाहिए।
API आंतरिक रूप से ऐड-इन की ओर से UI ईवेंट की सदस्यता लेगा और फिर API क्लाइंट को संबंधित "आवरण" ईवेंट को उजागर करके ईवेंट को दर्शाता है। आपके API को कुछ हुक की पेशकश करनी चाहिए जहां ऐड-इन विशिष्ट एप्लिकेशन घटकों तक पहुंचने के लिए कनेक्ट हो सकता है। एक प्लगइन एपीआई एक एडेप्टर या मुखौटे की तरह कार्य करता है ताकि बाहरी लोगों को आंतरिक तक पहुंच मिल सके।
अलगाव की डिग्री की अनुमति देने के लिए।
विज़ुअल स्टूडियो कैसे प्लग इन का प्रबंधन करता है या हमें उन्हें कार्यान्वित करने की अनुमति देता है इस पर एक नज़र डालें। Pretend आप विजुअल स्टूडियो के लिए एक प्लगइन लिखना चाहते हैं और यह कैसे करना है पर कुछ शोध करते हैं। आपको एहसास होगा कि विज़ुअल स्टूडियो एक इंटरफेस या एपीआई के माध्यम से अपने इंटर्नल को उजागर करता है। ईजी आप कोड संपादक में हेरफेर कर सकते हैं या इसके वास्तविक उपयोग के बिना संपादक की सामग्री के बारे में जानकारी प्राप्त कर सकते हैं ।
Aync/Await
कि ऑपरेशन A को करने और उस ऑपरेशन STATE को सहेजने के बारे में अब आप चाहते हैं कि उपयोगकर्ता ग्रिड पर क्लिक करें। यदि उपयोगकर्ता क्लिक करता है तो आप राज्य की जांच करते हैं यदि सत्य है तो क्या आपका ऑपरेशन बाकी है जो आप करना चाहते हैं?