.NET रिएक्टिव एक्सटेंशन में विषयों की सिफारिश क्यों नहीं की जाती है?


111

मैं वर्तमान में .NET के लिए रिएक्टिव एक्सटेंशन्स फ्रेमवर्क के साथ ग्रिप कर रहा हूँ और मैं अपने विभिन्न परिचय संसाधनों (मुख्य रूप से http://www.introtorx.com ) के माध्यम से अपना काम कर रहा हूँ

हमारे आवेदन में कई हार्डवेयर इंटरफेस शामिल हैं जो नेटवर्क फ़्रेम का पता लगाते हैं, ये मेरे IObservables होंगे, फिर मेरे पास विभिन्न प्रकार के घटक हैं जो उन फ़्रेमों का उपभोग करेंगे या डेटा पर कुछ प्रकार के परिवर्तन करेंगे और एक नए प्रकार के फ़्रेम का उत्पादन करेंगे। अन्य घटक भी होंगे जिन्हें उदाहरण के लिए प्रत्येक n'th फ्रेम को प्रदर्शित करने की आवश्यकता है। मुझे विश्वास है कि Rx हमारे अनुप्रयोग के लिए उपयोगी होने जा रहा है, हालाँकि मैं IObserver इंटरफ़ेस के कार्यान्वयन विवरण से जूझ रहा हूँ।

मेरे द्वारा पढ़े जा रहे संसाधनों के अधिकांश (यदि सभी नहीं) ने कहा है कि मुझे स्वयं IObservable इंटरफ़ेस को लागू नहीं करना चाहिए, लेकिन दिए गए कार्यों या कक्षाओं में से एक का उपयोग करना चाहिए। मेरे शोध से यह प्रतीत होता है कि एक बनाने से Subject<IBaseFrame>मुझे वह मिलेगा जो मुझे चाहिए, मेरे पास मेरा एक धागा होगा जो हार्डवेयर इंटरफ़ेस से डेटा पढ़ता है और फिर मेरे Subject<IBaseFrame>उदाहरण के OnNext फ़ंक्शन को कॉल करता है । विभिन्न IObserver घटकों को तब उस विषय से उनकी सूचनाएं प्राप्त होंगी।

मेरा भ्रम इस ट्यूटोरियल के परिशिष्ट में दिए गए सलाह से आ रहा है जहाँ यह कहता है:

विषय प्रकारों के उपयोग से बचें। आरएक्स प्रभावी रूप से एक कार्यात्मक प्रोग्रामिंग प्रतिमान है। विषयों का उपयोग करने का मतलब है कि अब हम राज्य का प्रबंधन कर रहे हैं, जो संभावित रूप से परिवर्तनशील है। एक ही समय में उत्परिवर्तन की स्थिति और अतुल्यकालिक प्रोग्रामिंग दोनों से निपटना सही होने के लिए बहुत कठिन है। इसके अलावा, कई ऑपरेटरों (विस्तार विधियों) को यह सुनिश्चित करने के लिए सावधानीपूर्वक लिखा गया है कि सदस्यता और अनुक्रम का सही और सुसंगत जीवनकाल बनाए रखा जाए; जब आप विषयों का परिचय देते हैं, तो आप इसे तोड़ सकते हैं। यदि आप स्पष्ट रूप से विषयों का उपयोग करते हैं तो भविष्य के रिलीज़ में महत्वपूर्ण प्रदर्शन में गिरावट देखी जा सकती है।

मेरा आवेदन काफी महत्वपूर्ण है, मैं स्पष्ट रूप से उत्पादन कोड में जाने से पहले आरएक्स पैटर्न का उपयोग करने के प्रदर्शन का परीक्षण करने जा रहा हूं; हालाँकि मुझे चिंता है कि मैं कुछ ऐसा कर रहा हूँ जो कि Subject क्लास का उपयोग करके Rx फ्रेमवर्क की भावना के विरुद्ध है और फ्रेमवर्क के भविष्य के संस्करण में प्रदर्शन को नुकसान पहुंचाने वाला है।

क्या मुझे जो चाहिए वो करने का एक बेहतर तरीका है? हार्डवेयर पोलिंग थ्रेड लगातार चल रहा है कि क्या कोई पर्यवेक्षक हैं या नहीं (एचडब्ल्यू बफर बैकअप देगा अन्यथा), इसलिए यह बहुत गर्म अनुक्रम है। मुझे तब कई पर्यवेक्षकों को प्राप्त फ्रेम पास करने की आवश्यकता है।

किसी भी सलाह की काफी सराहना की जाएगी।


1
यह वास्तव में इस विषय को समझने में मेरी मदद करता है, मैं बस अपने सिर में चीजों को सीधे प्राप्त कर रहा हूं कि इसे अपने आवेदन में कैसे उपयोग किया जाए। मुझे पता है कि वे सही काम कर रहे हैं - मेरे पास घटकों का एक पाइप लाइन है जो बहुत धक्का उन्मुख है और मुझे जीयूआई में प्रदर्शित करने के लिए यूआई थ्रेड पर सभी प्रकार के फ़िल्टरिंग और इनवॉइस करने की आवश्यकता है और साथ ही अंतिम प्राप्त फ्रेम आदि को बफर करना है। आदि - मुझे सिर्फ यह सुनिश्चित करने की ज़रूरत है कि मैं इसे पहली बार करूं!
एंथनी

जवाबों:


70

ठीक है, अगर हम अपने हठधर्मी तरीकों को अनदेखा करते हैं और "सभी अच्छे / बुरे हैं" विषयों को एक साथ अनदेखा करते हैं। आइए हम समस्या स्थान को देखें।

मुझे यकीन है कि या तो आपके पास प्रणाली की 2 शैलियों में से 1 है जिसे आपको करने की आवश्यकता है।

  1. संदेश आने पर सिस्टम एक घटना या कॉल बैक करता है
  2. यह देखने के लिए कि क्या कोई प्रक्रिया करने के लिए कोई संदेश है, आपको सिस्टम को चुनने की आवश्यकता है

विकल्प 1 के लिए, आसान है, हम इसे उचित FromEvent विधि के साथ लपेटते हैं और हम कर रहे हैं। पब में!

विकल्प 2 के लिए, हमें अब इस पर विचार करने की आवश्यकता है कि हम इसे कैसे मतदान करते हैं और इसे कैसे प्रभावी ढंग से करते हैं। इसके अलावा जब हम मूल्य प्राप्त करते हैं, तो हम इसे कैसे प्रकाशित करते हैं?

मुझे लगता है कि आप मतदान के लिए एक समर्पित धागा चाहते हैं। आप कुछ अन्य कोडर को थ्रेडपूल / टास्कपूल पर हथौड़ा चलाना और थ्रेडपूल भुखमरी की स्थिति में नहीं छोड़ना चाहेंगे। वैकल्पिक रूप से आप संदर्भ स्विचिंग की परेशानी नहीं चाहते (मुझे लगता है)। तो मान लें कि हमारे पास अपना धागा है, हम शायद किसी प्रकार का / सो लूप करेंगे जो हम चुनाव में बैठते हैं। जब चेक में कुछ संदेश मिलते हैं तो हम उन्हें प्रकाशित करते हैं। खैर यह सब देखने के लिए एकदम सही लगता है। अब हम शायद थोड़ी देर के लूप का उपयोग नहीं कर सकते क्योंकि अभ्यस्त हमें रद्द करने की अनुमति देने के लिए डिस्पोजेबल को वापस करने की अनुमति देते हैं। सौभाग्य से आपने पूरी किताब पढ़ी है इसलिए रिकर्सिव शेड्यूलिंग के जानकार हैं!

मुझे लगता है कि कुछ इस तरह से काम कर सकता है। #टेस्ट नहीं हुआ

public class MessageListener
{
    private readonly IObservable<IMessage> _messages;
    private readonly IScheduler _scheduler;

    public MessageListener()
    {
        _scheduler = new EventLoopScheduler();

        var messages = ListenToMessages()
                                    .SubscribeOn(_scheduler)
                                    .Publish();

        _messages = messages;
        messages.Connect();
    }

    public IObservable<IMessage> Messages
    {
        get {return _messages;}
    }

    private IObservable<IMessage> ListenToMessages()
    {
        return Observable.Create<IMessage>(o=>
        {
                return _scheduler.Schedule(recurse=>
                {
                    try
                    {           
                        var messages = GetMessages();
                        foreach (var msg in messages)
                        {
                            o.OnNext(msg);
                        }   
                        recurse();
                    }
                    catch (Exception ex)
                    {
                        o.OnError(ex);
                    }                   
                });
        });
    }

    private IEnumerable<IMessage> GetMessages()
    {
         //Do some work here that gets messages from a queue, 
         // file system, database or other system that cant push 
         // new data at us.
         // 
         //This may return an empty result when no new data is found.
    }
}

कारण मुझे वास्तव में विषय पसंद नहीं है, यह आमतौर पर डेवलपर का मामला है जो वास्तव में समस्या पर एक स्पष्ट डिजाइन नहीं है। एक विषय में हैक करें, इसे वहां और हर जगह पर प्रहार करें, और फिर डब्ल्यूटीएफ पर खराब समर्थन देव अनुमान लगा दें। जब आप क्रिएट / जनरेट आदि विधियों का उपयोग करते हैं तो आप अनुक्रम पर प्रभाव को स्थानीय कर रहे हैं। आप यह सब एक विधि से देख सकते हैं और आप जानते हैं कि कोई और नहीं एक बुरा साइड इफेक्ट में फेंक रहा है। अगर मुझे एक विषय क्षेत्र दिखाई देता है तो मुझे अब एक कक्षा में सभी स्थानों की तलाश में जाना होगा। यदि कुछ एमएफर सार्वजनिक रूप से उजागर करता है, तो सभी दांव बंद हो जाते हैं, कौन जानता है कि इस अनुक्रम का उपयोग कैसे किया जा रहा है! Async / Concurrency / Rx कठिन है। आपको अपने सिर को और अधिक स्पिन करने के लिए साइड इफेक्ट्स और कारण प्रोग्रामिंग की अनुमति देकर इसे कठिन बनाने की आवश्यकता नहीं है।


10
मैं अभी इस उत्तर को पढ़ रहा हूं, लेकिन मुझे लगा कि मुझे यह इंगित करना चाहिए कि मैं विषय इंटरफ़ेस को उजागर करने पर कभी विचार नहीं करूंगा! मैं इसका उपयोग एक सील वर्ग के भीतर IObservable <> कार्यान्वयन प्रदान करने के लिए कर रहा हूं (जो IObservable <> को उजागर करता है)। मैं निश्चित रूप से देख सकता हूँ कि विषय को उजागर करना <> इंटरफ़ेस एक बुरी बात क्यों होगी
एंथनी

हे, माफ करना, मोटा होना, लेकिन मैं वास्तव में आपके कोड को नहीं समझता। ListenToMessages () और GetMessages () क्या कर रहे हैं और लौट रहे हैं?
user10479

1
आपकी व्यक्तिगत परियोजना @jeromerg के लिए, यह ठीक हो सकता है। हालांकि मेरे अनुभव डेवलपर्स में WPF, MVVM, यूनिट टेस्टिंग GUI डिजाइन के साथ संघर्ष करते हैं और फिर Rx में फेंकने से चीजें और अधिक जटिल हो सकती हैं। मैंने BehaviourSubject-as-a-property पैटर्न की कोशिश की है। हालाँकि मैंने पाया कि अगर हम मानक INPC गुणों का उपयोग करते हैं और फिर इसे IObservable में बदलने के लिए एक साधारण एक्सटेंशन विधि का उपयोग करते हैं, तो यह दूसरों के लिए बहुत अधिक योग्य था। इसके अतिरिक्त, आपको अपने व्यवहार विषयों के साथ काम करने के लिए कस्टम WPF बाइंडिंग की आवश्यकता होगी। अब आपकी खराब टीम को WPF, MVVM, Rx और आपके नए ढांचे को भी सीखना है।
ली कैंपबेल

2
@LeeCampbell, इसे अपने कोड उदाहरण के रूप में रखने के लिए, सामान्य तरीका यह होगा कि MessageListener का निर्माण सिस्टम द्वारा किया जाता है (आप शायद किसी तरह वर्ग का नाम पंजीकृत करें), और आपको बताया जाता है कि सिस्टम तब OnCreate () को कॉल करेगा। OnGoodbye (), और message1 के रूप में message1 (), message2 (), और message3 () कॉल करेंगे। ऐसा लगता है कि संदेश [123] एक विषय पर OnNext को बुलाएगा, लेकिन क्या कोई बेहतर तरीका है?
जेम्स मूर

1
@JamesMoore के रूप में इन चीजों को ठोस उदाहरणों के साथ समझाने में बहुत आसान है। यदि आप एक ओपन सोर्स एंड्रॉइड ऐप के बारे में जानते हैं जो आरएक्स और सब्जेक्ट्स का उपयोग करता है, तो शायद मुझे यह देखने के लिए समय मिल सकता है कि क्या मैं एक बेहतर तरीका प्रदान कर सकता हूं। मैं समझता हूं कि यह बहुत उपयोगी नहीं है कि यह एक कुरसी पर खड़ा हो और कहे कि विषय खराब हैं। लेकिन मुझे लगता है कि IntroToRx, RxCookbook और ReactiveTrader जैसी चीजें सभी Rx का उपयोग करने के उदाहरण के विभिन्न स्तर देती हैं।
ली कैंपबेल

38

सामान्य तौर पर आपको उपयोग करने से बचना चाहिए Subject, हालांकि आप जिस चीज के लिए यहां कर रहे हैं मुझे लगता है कि वे काफी अच्छी तरह से काम करती हैं। जब मैंने Rx ट्यूटोरियल में "विषयों से बचें" संदेश आया तो मैंने एक समान प्रश्न पूछा ।

के शब्दों में डेव सेक्सटन (Rxx का)

"विषय आरएक्स के स्टेटफुल घटक हैं। वे तब उपयोगी होते हैं, जब आपको एक फ़ील्ड या स्थानीय चर के रूप में एक घटना-जैसी अवलोकन बनाने की आवश्यकता होती है।"

मैं उनका उपयोग Rx में प्रवेश बिंदु के रूप में करता हूं। इसलिए अगर मेरे पास कुछ कोड है जो 'कुछ हुआ' (जैसे आपके पास है) कहने की आवश्यकता है, तो मैं एक का उपयोग करता हूं Subjectऔर कॉल करता हूं OnNext। फिर यह बताएं कि IObservableदूसरों के लिए सदस्यता लेने के लिए (आप AsObservable()अपने विषय पर उपयोग कर सकते हैं यह सुनिश्चित करने के लिए कि कोई व्यक्ति किसी विषय पर नहीं जा सकता है और चीजों को गड़बड़ कर सकता है)।

आप इसे .NET इवेंट और उपयोग के साथ भी प्राप्त कर सकते हैं FromEventPattern, लेकिन अगर मैं केवल ईवेंट को किसी IObservableभी तरह चालू करने जा रहा हूं, तो मुझे इसके बजाय एक ईवेंट होने का लाभ नहीं दिखता है Subject(जिसका मतलब हो सकता है कि मैं गायब हूं यहाँ कुछ)

हालांकि, क्या आप काफी दृढ़ता से बचना चाहिए एक की सदस्यता है IObservableएक साथ Subject, यानी एक उत्तीर्ण नहीं होते हैं Subjectमें IObservable.Subscribeविधि।


आपको राज्य की आवश्यकता क्यों है? जैसा कि मेरे जवाब से पता चलता है, यदि आप समस्या को अलग-अलग टुकड़ों में तोड़ते हैं, तो आपको वास्तव में राज्य का प्रबंधन करने की आवश्यकता नहीं है। इस मामले में विषयों का उपयोग नहीं किया जाना चाहिए
कैस्पर ओने

8
@casperOne आपको विषय <T> या ईवेंट के बाहर की आवश्यकता नहीं है (जिसमें कॉल, ऑब्जर्वर या ईवेंट हैंडलर के लिए दोनों चीजों का संग्रह है)। मैं सिर्फ एक विषय का उपयोग करना पसंद करता हूं यदि किसी ईवेंट को जोड़ने का एकमात्र कारण इसे FromEventPattern के साथ लपेटना है। अपवाद स्कीमाटिक्स में बदलाव के अलावा, जो आपके लिए महत्वपूर्ण हो सकता है, मुझे इस तरह से विषय से बचने का कोई लाभ नहीं दिखता है। फिर, मैं यहाँ कुछ और याद कर रहा हूँ कि यह घटना विषय के लिए बेहतर है। राज्य का उल्लेख सिर्फ बोली का हिस्सा था, और इसे छोड़ना बेहतर लग रहा था। शायद यह उस हिस्से के बिना स्पष्ट है?
विल्का

@casperOne - लेकिन आप इसे केवल FromEventPattern के साथ लपेटने के लिए एक ईवेंट नहीं बनाएं। यह स्पष्ट रूप से एक भयानक विचार है।
जेम्स मूर

3
मैंने अपने उद्धरण को इस ब्लॉग पोस्ट में और अधिक गहराई से समझाया है ।
डेव सेक्सटन

मैं उनका उपयोग Rx में प्रवेश बिंदु के रूप में करता हूं। इसने मेरे लिए सिर पर कील ठोक दी। मेरे पास एक ऐसी स्थिति है जहां एक एपीआई है जब आह्वान उन घटनाओं को उत्पन्न करता है जो मैं प्रतिक्रियाशील प्रसंस्करण पाइपलाइन से गुजरना चाहता हूं। सब्जेक्ट मेरे लिए जवाब था, क्योंकि RxJava AFAICT में FromEventPattern मौजूद नहीं है।
स्कॉर्पियोडावग

31

अक्सर जब आप एक विषय का प्रबंधन कर रहे होते हैं, तो आप वास्तव में Rx में पहले से ही सुविधाओं को फिर से लागू कर रहे होते हैं, और शायद यह उतना मजबूत, सरल और एक्स्टेंसिबल तरीका नहीं है।

जब आप Rx में कुछ अतुल्यकालिक डेटा प्रवाह को अनुकूलित करने का प्रयास कर रहे हों (या एक अतुल्यकालिक डेटा प्रवाह को उस एक से उत्पन्न करें जो वर्तमान में अतुल्यकालिक नहीं है), तो सबसे आम मामले आमतौर पर हैं:

  • डेटा का स्रोत एक घटना है : जैसा कि ली कहते हैं, यह सबसे सरल मामला है: FromEvent और पब में सिर का उपयोग करें।

  • डेटा का स्रोत एक तुल्यकालिक ऑपरेशन से है और आप मतदान अपडेट चाहते हैं , (उदाहरण के लिए एक वेबसेवा या डेटाबेस कॉल): इस मामले में आप ली के सुझाए गए दृष्टिकोण का उपयोग कर सकते हैं, या साधारण मामलों के लिए, आप कुछ का उपयोग कर सकते हैं Observable.Interval.Select(_ => <db fetch>)। जब आप स्रोत डेटा में कुछ भी नहीं बदला है तो प्रकाशन अद्यतन को रोकने के लिए आप DistinctUntilChanged () का उपयोग करना चाह सकते हैं।

  • डेटा का स्रोत कुछ प्रकार की अतुल्यकालिक एपी है जो आपके कॉलबैक को कॉल करता है : इस मामले में, ऑब्जर्वर पर OnNext / OnError / OnComplete को कॉल करने के लिए अपने कॉलबैक को हुक करने के लिए Observable.Create का उपयोग करें।

  • डेटा का स्रोत एक कॉल है जो नए डेटा उपलब्ध होने तक ब्लॉक करता है (उदाहरण के लिए कुछ सिंक्रोनस सॉकेट रीड ऑपरेशंस): इस मामले में, आप ऑब्ज़र्वेबल का उपयोग कर सकते हैं। सॉकेट से पढ़े जाने वाले अनिवार्य कोड को लपेटने के लिए ऑब्ज़र्वर का प्रयोग करें। जब डेटा पढ़ा जाता है। यह आपके द्वारा किए जा रहे विषय के समान हो सकता है।

Observable.Create बनाम एक वर्ग का उपयोग करना जो एक ऐसे विषय का निर्माण करता है जो उपज कीवर्ड का उपयोग करने के लिए काफी समान है बनाम एक पूरी कक्षा का निर्माण करता है जो IEnumerator लागू करता है। बेशक, आप एक IEnumerator को साफ सुथरा और उपज कोड के रूप में एक अच्छा नागरिक लिख सकते हैं, लेकिन कौन सा बेहतर रूप से समझाया गया है और एक neater डिजाइन महसूस करता है? ऑब्जर्वेबल के लिए भी यही सच है। क्रिएट बनाम मैनेजिंग सब्जेक्ट्स।

Observable.Create आपको आलसी सेटअप और स्वच्छ फाड़ के लिए एक साफ पैटर्न देता है। सब्जेक्ट रैप करने वाले क्लास के साथ आप इसे कैसे हासिल करते हैं? आपको किसी प्रकार की प्रारंभ विधि की आवश्यकता है ... आप कैसे जानते हैं कि इसे कब कॉल करना है? या क्या आप हमेशा इसे शुरू करते हैं, तब भी जब कोई नहीं सुन रहा हो? और जब आप कर रहे हैं, तो आपको यह कैसे मिलता है कि सॉकेट से पढ़ना बंद हो जाए / डेटाबेस को मतदान करना, आदि। आपके पास किसी प्रकार की रोक विधि है, और आपको अभी भी न केवल उस IObservable तक पहुंच प्राप्त है, जिसकी आपको सदस्यता दी गई है, लेकिन उस वर्ग को जिसने पहले स्थान पर विषय बनाया है।

ओब्जर्वेबल के साथ। क्रिएट, यह सब एक ही जगह पर लिपटा हुआ है। Observable.Create की बॉडी तब तक नहीं चलती है जब तक कोई सब्सक्राइब नहीं करता है, इसलिए अगर कोई सब्सक्राइब नहीं करता है, तो आप कभी भी अपने संसाधन का इस्तेमाल नहीं करते हैं। और ऑब्जर्वेबल। क्रिएट एक ऐसे डिस्पोजेबल को लौटाता है जो आपके संसाधन / कॉलबैक इत्यादि को आसानी से बंद कर सकता है - यह तब कहा जाता है जब ऑब्जर्वर अनसब्सक्राइब करता है। वे संसाधन जिन्हें आप अवलोकन योग्य बनाने के लिए उपयोग कर रहे हैं, उनके जीवनकाल बड़े ही करीने से वेधशाला के जीवनकाल से जुड़े हैं।


1
अवलोकनीय की बहुत स्पष्ट व्याख्या। धन्यवाद!
इवान मोरन

1
मेरे पास अभी भी ऐसे मामले हैं जहां मैं किसी विषय का उपयोग करता हूं, जहां एक ब्रोकर ऑब्जेक्ट ऑब्जर्वेबल को उजागर करता है (कहते हैं कि यह सिर्फ एक अस्थिर संपत्ति है)। विभिन्न घटक ब्रोकर को यह बताएंगे कि संपत्ति में बदलाव कब होता है (विधि कॉल के साथ), और यह विधि एक OnNext करती है। उपभोक्ता सदस्यता लेते हैं। मुझे लगता है कि मैं इस मामले में एक व्यवहार-विषय का उपयोग करूंगा, क्या यह उचित है?
फ्रैंक श्वेतेरमैन

1
यह स्थिति पर निर्भर करता है। अच्छा आरएक्स डिज़ाइन सिस्टम को एक एसिंक्स / प्रतिक्रियाशील वास्तुकला की ओर परिवर्तित करता है। यह एक प्रणाली है कि अनिवार्य डिजाइन के साथ प्रतिक्रियाशील कोड के छोटे घटकों को सफाई से एकीकृत करने के लिए कठिन हो सकता है। बैंड सहायता समाधान अधीन क्रियाओं का उपयोग करने के लिए अनिवार्य घटनाओं (फ़ंक्शन कॉल, प्रॉपर्टी सेट) को अवलोकन योग्य घटनाओं में बदलने के लिए है। फिर आप प्रतिक्रियात्मक कोड की थोड़ी जेब और कोई वास्तविक "अहा!" पल। डेटा प्रवाह के लिए डिज़ाइन में परिवर्तन करना और उस पर प्रतिक्रिया करना आमतौर पर एक बेहतर डिज़ाइन देता है, लेकिन यह एक व्यापक परिवर्तन है और इसके लिए एक मानसिकता बदलाव और टीम खरीदने की आवश्यकता होती है।
निल कनॉटघटन

1
मैं यहां बताऊंगा (Rx के रूप में अनुभवहीन) कि: Subjects का उपयोग करके आप Rx की दुनिया में एक बड़ी अनिवार्यता के भीतर प्रवेश कर सकते हैं और इसे धीरे-धीरे बदल सकते हैं। पहले अनुभवों को हासिल करने के लिए .... और निश्चित रूप से बाद में अपने कोड को बदलें कि यह शुरुआत (लोल) से कैसे होना चाहिए था। लेकिन मुझे लगता है कि विषयों के उपयोग से यह सार्थक हो सकता है।
रोबेटो

9

उद्धृत ब्लॉक टेक्स्ट बहुत अधिक बताता है कि आप का उपयोग क्यों नहीं किया जाना चाहिए Subject<T>, लेकिन इसे सरल बनाने के लिए, आप पर्यवेक्षक और अवलोकन के कार्यों को जोड़ रहे हैं, जबकि बीच में कुछ प्रकार की स्थिति को इंजेक्ट कर रहे हैं (चाहे आप एनकैप्सुलेट कर रहे हैं या विस्तारित कर रहे हैं)।

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

कहा कि आपके विशिष्ट मामले में, मैं सुझाव दूंगा कि आप अपनी चिंताओं को छोटे भागों में तोड़ें।

सबसे पहले, आपके पास अपना धागा है जो गर्म है, और हमेशा संकेतों को मॉनिटर करने के लिए हार्डवेयर की निगरानी कर रहा है। आप इसे सामान्य रूप से कैसे करेंगे? घटनाएँ । तो चलिए शुरू करते हैं।

चलो परिभाषित करते हैं EventArgsकि आपकी घटना आग लग जाएगी।

// The event args that has the information.
public class BaseFrameEventArgs : EventArgs
{
    public BaseFrameEventArgs(IBaseFrame baseFrame)
    {
        // Validate parameters.
        if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");

        // Set values.
        BaseFrame = baseFrame;
    }

    // Poor man's immutability.
    public IBaseFrame BaseFrame { get; private set; }
}

अब, घटना को आग लगाने वाला वर्ग। ध्यान दें, यह एक स्थिर वर्ग हो सकता है (चूंकि आपके पास हमेशा हार्डवेयर बफर की निगरानी करने वाला एक थ्रेड होता है), या कुछ ऐसा जिसे आप ऑन-डिमांड कहते हैं, जो उसकी सदस्यता लेता है । आपको इसे उपयुक्त रूप में संशोधित करना होगा।

public class BaseFrameMonitor
{
    // You want to make this access thread safe
    public event EventHandler<BaseFrameEventArgs> HardwareEvent;

    public BaseFrameMonitor()
    {
        // Create/subscribe to your thread that
        // drains hardware signals.
    }
}

तो अब आपके पास एक वर्ग है जो एक घटना को उजागर करता है। वेधशालाएँ घटनाओं के साथ अच्छी तरह से काम करती हैं। इतना है कि IObservable<T>अगर आप मानक घटना पैटर्न का पालन करते हैं, तो कक्षा पर स्थिर FromEventPatternविधि के माध्यम से घटनाओं की धाराओं को परिवर्तित करने के लिए प्रथम श्रेणी का समर्थन होता है ।Observable

आपके ईवेंट, और FromEventPatternविधि के स्रोत के साथ , हम एक IObservable<EventPattern<BaseFrameEventArgs>>आसानी से बना सकते हैं ( EventPattern<TEventArgs>वर्ग एबीएस घटना में आपको जो दिखता है, वह उल्लेखनीय रूप से, उदाहरण के लिए, उदाहरण EventArgsऔर प्रेषक का प्रतिनिधित्व करने वाली एक वस्तु) से बना सकता है, जैसे:

// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();

// Create the observable.  It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
    FromEventPattern<BaseFrameEventArgs>(
        h => source.HardwareEvent += h,
        h => source.HardwareEvent -= h);

बेशक, आप एक चाहते हैं IObservable<IBaseFrame>, लेकिन एक प्रक्षेपण बनाने के लिए कक्षा पर Selectविस्तार विधि का उपयोग करके Observable(जैसे आप LINQ में होगा, और हम यह सब एक आसान-से-उपयोग विधि में लपेट सकते हैं):

public IObservable<IBaseFrame> CreateHardwareObservable()
{
    // The event source.
    // Or you might not need this if your class is static and exposes
    // the event as a static event.
    var source = new BaseFrameMonitor();

    // Create the observable.  It's going to be hot
    // as the events are hot.
    IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
        FromEventPattern<BaseFrameEventArgs>(
            h => source.HardwareEvent += h,
            h => source.HardwareEvent -= h);

    // Return the observable, but projected.
    return observable.Select(i => i.EventArgs.BaseFrame);
}

7
आपकी प्रतिक्रिया @casperOne के लिए धन्यवाद, यह मेरा प्रारंभिक दृष्टिकोण था, लेकिन यह एक घटना को जोड़ने के लिए "गलत" लगा, ताकि मैं इसे आरएक्स के साथ लपेट सकूं। मैं वर्तमान में प्रतिनिधियों का उपयोग करता हूं (और हाँ, मुझे पता है कि लोडिंग और बचत कॉन्फ़िगरेशन के लिए उपयोग किए गए कोड के साथ फिट होने के लिए यही एक घटना है!), यह घटक पाइपलाइनों को फिर से बनाने में सक्षम होना चाहिए और प्रतिनिधि प्रणाली ने मुझे सबसे अधिक दिया लचीलापन। आरएक्स मुझे अब इस क्षेत्र में सिरदर्द दे रहा है, लेकिन फ्रेमवर्क में बाकी सब कुछ की शक्ति विन्यास समस्या को हल कर रही है।
एंथनी

@Anthony यदि आप काम करने के लिए उसका कोड नमूना प्राप्त कर सकते हैं, तो बढ़िया, लेकिन जैसा कि मैंने टिप्पणी की है, इसका कोई मतलब नहीं है। जैसा कि "गलत" महसूस करने के लिए, मुझे नहीं पता कि तार्किक भागों में चीजों को विभाजित करना "गलत" क्यों लगता है, लेकिन आपने अपने मूल पोस्ट में पर्याप्त विवरण नहीं दिया है कि यह इंगित करने के लिए IObservable<T>कि आप इसे कैसे करें के बारे में कोई जानकारी नहीं है। वर्तमान में उस सूचना के साथ संकेत दिया गया है।
कैस्पर ओने

@casperOne आपकी राय में, क्या सब्जेक्ट्स का उपयोग एक मैसेज बस / इवेंट एग्रीगेटर के लिए उचित होगा?
किट्यून

1
@kitsune नहीं, मैं नहीं देखता कि वे क्यों करेंगे। यदि आप "अनुकूलन" सोच रहे हैं, तो आपको यह सवाल पूछना होगा कि क्या समस्या है या नहीं, क्या आपने समस्या का कारण होने के लिए आरएक्स को मापा है?
कैस्परऑन

2
मैं यहां कैस्पर ओने से सहमत हूं कि चिंताओं को दूर करना एक अच्छा विचार है। मैं यह बताना चाहूंगा कि यदि आप हार्डवेयर से ईवेंट Rx पैटर्न पर जाते हैं, तो आप त्रुटि शब्दार्थ खो देते हैं। किसी भी खोए कनेक्शन या सत्र आदि को उपभोक्ता के सामने उजागर नहीं किया जाएगा। अब कंज्यूमर कैंट तय कर सकता है कि वे रिट्रीट करना, डिसकनेक्ट करना, किसी अन्य सीक्वेंस को सब्सक्राइब करना चाहते हैं या कुछ और।
ली कैंपबेल

0

यह सामान्य है कि विषय सार्वजनिक इंटरफ़ेस के लिए उपयोग करने के लिए अच्छे नहीं हैं। हालांकि यह निश्चित रूप से सच है, कि यह वह तरीका नहीं है जिस तरह से प्रतिक्रियाशील प्रोग्रामिंग दृष्टिकोण को देखना चाहिए, यह निश्चित रूप से आपके क्लासिक कोड के लिए एक अच्छा सुधार / रीफैक्टरिंग विकल्प है।

यदि आपके पास एक सार्वजनिक सेट एक्सेसर के साथ एक सामान्य संपत्ति है और आप परिवर्तनों के बारे में सूचित करना चाहते हैं, तो व्यवहार व्यवहार के साथ इसे बदलने के खिलाफ कुछ भी नहीं बोलता है। INPC या अतिरिक्त अन्य घटनाएं सिर्फ इतनी साफ नहीं हैं और यह व्यक्तिगत रूप से मुझे बंद कर देती हैं। इस प्रयोजन के लिए आपको सामान्य संपत्तियों और खाई INPC या अन्य घटनाओं के बजाय सार्वजनिक गुणों के रूप में BehaviorSubjects का उपयोग करना चाहिए।

इसके अतिरिक्त विषय-इंटरफ़ेस आपके इंटरफ़ेस के उपयोगकर्ताओं को आपके गुणों की कार्यक्षमता के बारे में अधिक जागरूक बनाता है और केवल मूल्य प्राप्त करने के बजाय सदस्यता लेने की अधिक संभावना है।

यदि आप दूसरों को संपत्ति के परिवर्तनों को सुनने / उनकी सदस्यता लेने के लिए उपयोग करना चाहते हैं, तो इसका उपयोग करना सबसे अच्छा है।

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