क्या .NET का IObserver <T> कई IObservables की सदस्यता के लिए था?


9

हैं IObservable और IObserver .NET (भी इंटरफेस यहाँ और यहाँ )। दिलचस्प है, IObserver का ठोस कार्यान्वयन IObservable का प्रत्यक्ष संदर्भ नहीं रखता है। यह नहीं जानता कि यह किसकी सदस्यता है। यह केवल सदस्यता रद्द कर सकता है। "कृपया पिन को सदस्यता समाप्त करने के लिए खींचें।"

संपादित करें: unsubscriber लागू करता है IDisposable। मुझे लगता है, इस योजना को व्यपगत श्रोता समस्या को रोकने के लिए नियोजित किया गया था ।

दो बातें मेरे लिए पूरी तरह से स्पष्ट नहीं हैं, हालांकि।

  1. क्या इनर अनसब्सक्राइबर वर्ग सदस्यता और भूलने का व्यवहार प्रदान करता है? कौन और कब (बिल्कुल) IDisposable.Dispose()अनसब्सक्राइबर को कॉल करता है? कचरा संग्राहक (जीसी) नियतात्मक नहीं है।
    [अस्वीकरण: कुल मिलाकर, मैंने C और C ++ के साथ C # के साथ अधिक समय बिताया है।]
  2. यदि मैं एक पर्यवेक्षक K को एक पर्यवेक्षित L1 की सदस्यता देना चाहता हूं और पर्यवेक्षक को पहले से ही किसी अन्य पर्यवेक्षित L2 की सदस्यता लेनी चाहिए, तो क्या होना चाहिए?

    K.Subscribe(L1);
    K.Subscribe(L2);
    K.Unsubscribe();
    L1.PublishObservation(1003);
    L2.PublishObservation(1004);
    

    जब मैंने इस परीक्षण कोड को MSDN के उदाहरण के खिलाफ चलाया, तो पर्यवेक्षक L1 के लिए सदस्यता लिया। यह वास्तविक विकास में अजीबोगरीब होगा। संभावित रूप से, इसमें सुधार करने के लिए 3 रास्ते हैं:

    • यदि पर्यवेक्षक के पास पहले से ही एक सदस्यता रद्द उदाहरण है (यानी यह पहले से ही सदस्यता लिया हुआ है), तो यह नए प्रदाता की सदस्यता लेने से पहले मूल प्रदाता से चुपचाप सदस्यता समाप्त कर देता है। यह दृष्टिकोण इस तथ्य को छिपाता है कि यह अब मूल प्रदाता की सदस्यता नहीं है, जो बाद में एक आश्चर्य बन सकता है।
    • यदि पर्यवेक्षक के पास पहले से ही एक सदस्यता रद्द उदाहरण है, तो एक अपवाद है। एक सुव्यवस्थित कॉलिंग कोड को पर्यवेक्षक को स्पष्ट रूप से सदस्यता समाप्त करनी होगी।
    • पर्यवेक्षक कई प्रदाताओं की सदस्यता लेता है। यह सबसे पेचीदा विकल्प है, लेकिन क्या इसे IObservable और IObserver के साथ लागू किया जा सकता है? चलो देखते हैं। पर्यवेक्षक के लिए यह संभव है कि वह बिना स्रोत वाली वस्तुओं की सूची रखे: प्रत्येक स्रोत के लिए एक। दुर्भाग्य से, IObserver.OnComplete()उस प्रदाता को वापस संदर्भ नहीं देता जिसने इसे भेजा है। इसलिए, कई प्रदाताओं के साथ IObserver कार्यान्वयन यह निर्धारित करने में सक्षम नहीं होगा कि कौन से से सदस्यता समाप्त करना है।
  3. क्या .NET के IObserver को कई IObservables की सदस्यता लेने का इरादा था?
    क्या पर्यवेक्षक पैटर्न की पाठ्यपुस्तक की परिभाषा के लिए आवश्यक है कि एक पर्यवेक्षक को कई प्रदाताओं की सदस्यता लेने में सक्षम होना चाहिए? या यह वैकल्पिक और कार्यान्वयन पर निर्भर है?

जवाबों:


5

दो इंटरफेस वास्तव में रिएक्टिव एक्सटेंशन्स (आरएक्स फॉर शॉर्ट) का हिस्सा हैं, आपको उस लाइब्रेरी का उपयोग बहुत अधिक करना चाहिए जब भी आप उनका उपयोग करना चाहते हैं।

इंटरफेस तकनीकी रूप से mscrolib में हैं, Rx विधानसभाओं में से किसी में नहीं। मुझे लगता है कि यह इंटरऑपरेबिलिटी को कम करना है: इस तरह, टीपीएल डेटाफ्लो जैसी लाइब्रेरी सदस्यों को उन इंटरफेस के साथ काम कर सकती है , जो वास्तव में आरएक्स को संदर्भित किए बिना।

यदि आप Rx के Subjectअपने कार्यान्वयन के रूप में उपयोग करते हैं IObservable, तो Subscribeवह वापस IDisposableकर देगा जिसका उपयोग सदस्यता समाप्त करने के लिए किया जा सकता है:

var observable = new Subject<int>();

var unsubscriber =
    observable.Subscribe(Observer.Create<int>(i => Console.WriteLine("1: {0}", i)));
observable.Subscribe(Observer.Create<int>(i => Console.WriteLine("2: {0}", i)));

unsubscriber.Dispose();

observable.OnNext(1003);
observable.OnNext(1004);

5

बस कुछ चीजों को साफ करने के लिए जो कि आधिकारिक Rx डिजाइन दिशानिर्देशों में और मेरी वेब साइट IntroToRx.com पर लंबाई में प्रलेखित हैं :

  • आप अपनी ग्राहकी को साफ करने के लिए GC पर निर्भर नहीं रहते। यहां विस्तार से कवर किया गया है
  • कोई Unsubscribeविधि नहीं है। आप एक अवलोकन अनुक्रम की सदस्यता लेते हैं और एक सदस्यता दी जाती है । आप उस सदस्यता का निपटान कर सकते हैं जो यह दर्शाता है कि अब आप अपने कॉलबैक को लागू नहीं करना चाहते हैं।
  • एक अवलोकन अनुक्रम एक से अधिक बार पूरा नहीं किया जा सकता है (आरएक्स डिज़ाइन दिशानिर्देशों के अनुभाग 4 देखें)।
  • कई अवलोकन योग्य दृश्यों का उपभोग करने के कई तरीके हैं। वहाँ भी प्रतिक्रिया के बारे में जानकारी का एक धन है Reactivex.io और फिर से IntroToRx पर।

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

के बजाय

K.Subscribe(L1);
K.Subscribe(L2);
K.Unsubscribe();
L1.PublishObservation(1003);
L2.PublishObservation(1004);

जो सिर्फ छद्म कोड है और Rx के .NET कार्यान्वयन में काम नहीं करेगा, आपको निम्नलिखित कार्य करना चाहिए:

var source1 = new Subject<int>(); //was L1
var source2 = new Subject<int>(); //was L2

var subscription = source1
    .Merge(source2)
    .Subscribe(value=>Console.WriteLine("OnNext({0})", value));


source1.OnNext(1003);
source2.OnNext(1004);

subscription.Dispose();

अब यह प्रारंभिक प्रश्न पर पूरी तरह फिट नहीं है, लेकिन मुझे नहीं पता कि क्या K.Unsubscribe()करना चाहिए था (सभी से सदस्यता समाप्त, अंतिम या पहली सदस्यता?)


क्या मैं "ब्लॉक" का उपयोग करके सब्सक्रिप्शन ऑब्जेक्ट को केवल एन्सेक कर सकता हूं?
रॉबर्ट ओस्लर

1
इस तुल्यकालिक मामले में, आप Rx को अतुल्यकालिक माना जा सकता है। अतुल्यकालिक मामले में, आप सामान्य रूप से usingब्लॉक का उपयोग नहीं कर सकते हैं । सदस्यता विवरण के लिए लागत लगभग शून्य होनी चाहिए, इसलिए आप उपयोग करने वाले ब्लॉक को प्राप्त करेंगे, सदस्यता लें, उपयोग करने वाले ब्लॉक को छोड़ दें (इस प्रकार सदस्यता समाप्त करें) कोड को व्यर्थ बनाते हुए
ली कैंपबेल

3

आप सही हे। उदाहरण कई IObservables के लिए खराब काम करता है।

मुझे लगता है कि OnComplete () एक संदर्भ वापस प्रदान नहीं करता है क्योंकि वे नहीं चाहते हैं कि IObservable को इसे आसपास रखना होगा। अगर मैं लिख रहा था कि मैं शायद एक दूसरे पैरामीटर के रूप में एक पहचानकर्ता लेने के लिए कई सदस्यता का समर्थन करूंगा, जो कि OnComplete () कॉल पर वापस जाता है। तो आप कह सकते हैं

K.Subscribe(L1,"L1")
K.Subscribe(L2,"L2")
K.Unsubscribe("L1")

जैसा कि यह खड़ा है, यह प्रतीत होता है .NET IObserver कई पर्यवेक्षकों के लिए उपयुक्त नहीं है। लेकिन मुझे लगता है कि आपकी मुख्य वस्तु (उदाहरण में LocationReporter) हो सकती है

public Dictionary<String,IObserver> Observers;

और यह आपको समर्थन करने में सक्षम करेगा

K.Subscribe(L1,"L1")
K.Subscribe(L2,"L2")
K.Unsubscribe("L1")

भी।

मुझे लगता है कि Microsoft यह तर्क दे सकता है कि इसलिए उन्हें इंटरफेस में कई IObservables का सीधे समर्थन करने की कोई आवश्यकता नहीं है।


मैं यह भी सोच रहा था कि अवलोकन योग्य कार्यान्वयन में पर्यवेक्षकों की सूची हो सकती है। मैंने यह भी देखा है कि IObserver.OnComplete()यह पहचान नहीं करता है कि कॉल किसे आता है। यदि प्रेक्षक को एक से अधिक अवलोकनों की सदस्यता दी जाती है, तो यह नहीं पता होता है कि किससे अनसब्सक्राइब करना है। Anticlimactic। मुझे आश्चर्य है, क्या .NET में पर्यवेक्षक पैटर्न के लिए एक बेहतर इंटरफ़ेस है?
निक एलेक्सिव

यदि आप किसी चीज़ का संदर्भ चाहते हैं, तो आपको वास्तव में एक संदर्भ का उपयोग करना चाहिए, न कि एक स्ट्रिंग का।
ज़िक

इस जवाब ने मुझे वास्तविक जीवन की बग में मदद की। मैं Observable.Create()एक अवलोकन योग्य बनाने के लिए उपयोग कर रहा था , और कई स्रोत वेधशालाओं का उपयोग करके इसका उपयोग कर रहा था Subscribe()। मैंने अनजाने में एक कोड पथ में एक पूरा अवलोकन किया। इसने मेरे नए बनाए गए अवलोकन को पूरा किया, भले ही अन्य स्रोत पूर्ण नहीं थे। मुझे उम्र निकालने के लिए काम करने की ज़रूरत है - मुझे इसके लिए स्विच Observable.Empty()करना होगा Observable.Never()
ओली

0

मैं जानता हूँ कि यह है जिस तरह से पार्टी के लिए देर हो चुकी है, लेकिन ...

इंटरफेस मैं Observable<T>और आरएक्स का हिस्सा नहींIObserver<T> हैं ... वे मुख्य प्रकार हैं ... लेकिन आरएक्स उनका व्यापक उपयोग करता है।

आप जितने चाहें उतने (या कुछ) पर्यवेक्षकों के लिए स्वतंत्र हैं। यदि आप कई पर्यवेक्षकों का अनुमान लगाते हैं, तो OnNext()प्रत्येक अवलोकन घटना के लिए उपयुक्त पर्यवेक्षकों को कॉल रूट करने के लिए यह अवलोकन योग्य है । आपके द्वारा सुझाए गए अनुसार अवलोकन योग्य सूची या शब्दकोश की आवश्यकता हो सकती है।

केवल एक को अनुमति देने के लिए अच्छे मामले हैं - और कई को अनुमति देने के लिए अच्छे मामले हैं। उदाहरण के लिए, CQRS / ES कार्यान्वयन में, आप कमांड बस पर एक कमांड कमांडर प्रति कमांड प्रकार लागू कर सकते हैं , जबकि आप इवेंट स्टोर में दिए गए ईवेंट प्रकार के लिए कई रीड-साइड ट्रांसफॉर्म को सूचित कर सकते हैं।

जैसा कि अन्य उत्तरों में कहा गया है, कोई नहीं है Unsubscribe। जब आप Subscribeआम तौर पर गंदे काम करते हैं तो उस चीज का निपटान करना। प्रेक्षक, या एक एजेंट, जब तक यह आगे सूचना प्राप्त नहीं करना चाहता है, तब तक टोकन पर रखने के लिए जिम्मेदार है । (प्रश्न 1)

तो, आपके उदाहरण में:

K.Subscribe(L1);
K.Subscribe(L2);
K.Unsubscribe();
L1.PublishObservation(1003);
L2.PublishObservation(1004);

... यह अधिक पसंद किया जाएगा:

using ( var l1Token = K.Subscribe( L1 ) )
{
  using ( var l2Token = K.Subscribe( L2 );
  {
    L1.PublishObservation( 1003 );
    L2.PublishObservation( 1004 );
  } //--> effectively unsubscribing to L2 here

  L2.PublishObservation( 1005 );
}

... जहाँ K 1003 और 1004 नहीं बल्कि 1005 सुनेंगे।

मेरे लिए, यह अभी भी अजीब लग रहा है क्योंकि नाममात्र, सदस्यता लंबे समय से जीवित चीजें हैं ... अक्सर कार्यक्रम की अवधि के लिए। वे सामान्य .net ईवेंट के संबंध में इस बारे में असंतुष्ट नहीं हैं।

बहुत सारे उदाहरण मैंने देखे हैं, Disposeपर्यवेक्षक पर्यवेक्षक की पर्यवेक्षक सूची से पर्यवेक्षक को हटाने के लिए काम करता है। मैं पसंद करता हूं कि टोकन चारों ओर इतना ज्ञान न ले जाए ... और इसलिए मैंने अपनी सदस्यता के टोकन को सामान्य रूप से एक पास-इन लैंबडा को कॉल करने के लिए सामान्यीकृत किया है (सदस्यता-समय पर कैप्चर की गई जानकारी की पहचान के साथ:

public class SubscriptionToken<T>: IDisposable
{
  private readonly Action unsubscribe;

  private SubscriptionToken( ) { }
  public SubscriptionToken( Action unsubscribe )
  {
    this.unsubscribe = unsubscribe;
  }

  public void Dispose( )
  {
    unsubscribe( );
  }
}

... और देखने योग्य सदस्यता के दौरान सदस्यता समाप्त व्यवहार स्थापित कर सकते हैं:

IDisposable Subscribe<T>( IObserver<T> observer )
{
  var subscriberId = Guid.NewGuid( );
  subscribers.Add( subscriberId, observer );

  return new SubscriptionToken<T>
  (
    ( ) =>
    subscribers.Remove( subscriberId );
  );
}

यदि आपका पर्यवेक्षक कई वेधशालाओं से घटनाओं को पकड़ रहा है, तो आप यह सुनिश्चित करना चाह सकते हैं कि घटनाओं में किसी प्रकार की सहसंबंध संबंधी जानकारी स्वयं हो ... जैसे कि .net ईवेंट के साथ करते हैं sender। यह आपके ऊपर है कि क्या मायने रखता है या नहीं। जैसा कि आपने सही ढंग से तर्क दिया है, यह इसमें बेक नहीं है। (प्रश्न 3)

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