2011-10-09 4 views
18

यदि मेरे पास एक IObservable तक पहुंच है जो मुझे पता है कि केवल एक आइटम लौटने वाला है, तो यह काम करेगा और यह सबसे अच्छा उपयोग पैटर्न होगा?प्रतिक्रियाशील पर्यवेक्षण सदस्यता निपटान

IDisposable disposable = null; 
disposable = myObservable.Subscribe(x => 
    { 
    DoThingWithItem(x); 
    if (disposable != null) 
    { 
     disposable.Dispose(); 
    } 
    }); 
+1

IMHO तथ्य यह है कि एक निपटाए वस्तु दायरे में है यह एक बुरा शैली बनाता है। क्या मैं कुछ भूल रहा हूँ? –

+0

इसके द्वारा, क्या आपका मतलब यह है कि "डिस्पोजेबल" चर का निपटान किया जा सकता है यदि डिस्पोजेबल वैरिएबल से पहले मेरा ऑब्सर्जेबल आग लग जाती है? इस वस्तु का निपटान करने के लिए एक बेहतर पैटर्न क्या है? – Noob

उत्तर

9

अस्वीकरण: मैं अभी भी आरएक्स सीख रहा हूं। इसलिए मैं वास्तव में एक विशेषज्ञ नहीं हूं लेकिन मेरा मानना ​​है कि द्वारा लौटाई गई डिस्पोजेबल केवल सदस्यता सदस्यता समाप्त कर देगी। अगर स्रोत पूरा हो जाता है, जैसे आपके मामले में, सदस्यता रद्द हो जाती है। तो मुझे लगता है कि Dispose अनावश्यक है और इसे सुरक्षित रूप से हटाया जा सकता है।

अधिक जानकारी के लिए इस question का उत्तर देखें।

4

Take फ़ंक्शन ठीक वही करेगा जो आप खोज रहे हैं। इस मामले में, Take(1)

+2

आप क्या कहते हैं साबित किया जा सकता है? –

46

डिस्पोजेबल Subscribe विस्तार तरीकों से लौटे तो आप मैन्युअल नमूदार स्वाभाविक रूप से पहले समाप्त हो नमूदार से सदस्यता समाप्त करने की अनुमति देने के लिए पूरी तरह से दिया जाता है।

यदि अवलोकन योग्य हो - OnCompleted या OnError के साथ - तो सदस्यता पहले से ही आपके लिए निपटाई गई है। आप चलाते हैं तो आप के ऊपर है कि देखेंगे

var xs = Observable.Create<int>(o => 
{ 
    var d = Observable.Return(1).Subscribe(o); 
    return Disposable.Create(() => 
    { 
     Console.WriteLine("Disposed!"); 
     d.Dispose(); 
    }); 
}); 

var subscription = xs.Subscribe(x => Console.WriteLine(x)); 

:

इस कोड का प्रयास करें "निपटाई गई!" कंसोल पर लिखा जाता है जब सब्सक्रिप्शन को सदस्यता के बिना .Dispose() पर कॉल करने की आवश्यकता होती है।

एक महत्वपूर्ण बात गौर करने योग्य कचरा कलेक्टर कभी नहीं नमूदार सदस्यता पर .Dispose() कहता है, तो आप वे नहीं किया है अपनी सदस्यताओं की चाहिए निपटाने (या नहीं हो सकता है) स्वाभाविक रूप से समाप्त हो गया से पहले अपनी सदस्यता क्षेत्र से बाहर चला जाता है।

यह लो, उदाहरण के लिए:

var wc = new WebClient(); 

var ds = Observable 
    .FromEventPattern< 
     DownloadStringCompletedEventHandler, 
     DownloadStringCompletedEventArgs>(
      h => wc.DownloadStringCompleted += h, 
      h => wc.DownloadStringCompleted -= h); 

var subscription = 
    ds.Subscribe(d => 
     Console.WriteLine(d.EventArgs.Result)); 

ds नमूदार केवल ईवेंट हैंडलर को जोड़ देती है, जब यह एक सदस्यता है और केवल अलग होगा जब नमूदार पूर्ण करता है या सदस्यता का निपटारा किया जाता है। चूंकि यह एक ईवेंट हैंडलर है, अवलोकन करने योग्य कभी पूरा नहीं होगा क्योंकि यह अधिक घटनाओं की प्रतीक्षा कर रहा है, और इसीलिए घटना से अलग होने का एकमात्र तरीका है (उपरोक्त उदाहरण के लिए)।

जब आप एक FromEventPattern नमूदार आप जानते हैं कि केवल कभी एक मान प्रदान करेंगे तो यह ईवेंट हैंडलर स्वचालित रूप से अलग करने की अनुमति के लिए सदस्यता लेने से पहले .Take(1) विस्तार विधि को जोड़ने के लिए और फिर आप मैन्युअल रूप से के निपटान के लिए की जरूरत नहीं है बुद्धिमान है सदस्यता

तो जैसा

:

var ds = Observable 
    .FromEventPattern< 
     DownloadStringCompletedEventHandler, 
     DownloadStringCompletedEventArgs>(
      h => wc.DownloadStringCompleted += h, 
      h => wc.DownloadStringCompleted -= h) 
    .Take(1); 

मुझे आशा है कि इस मदद करता है।

+0

धन्यवाद! मेरे पास यह सटीक मुद्दा है (एक घटना जिसे मैं केवल एक चाहता हूं), और 'टेक (1) 'सही समाधान है। – moswald

+2

@moswald नोट 'FirstAsync()' वही काम करता है। – lobsterism

+1

'कचरा कलेक्टर कभी कॉल नहीं करता है। अवलोकन योग्य सदस्यता पर()() यह है कि मैं यहां था। धन्यवाद! –

0

कुछ टिप्पणियों के विपरीत यह OnNext के अंदर से सदस्यता का निपटान करने के लिए बिल्कुल असामान्य नहीं है।

हालांकि यह सच है कि OnCompleted और OnError पर निपटान एक लिपटे सदस्यता Subscribe विस्तार विधि बनाता द्वारा आप के लिए किया जाता है, तो आप एक मूल्य आप देख रहे हैं के आधार पर सदस्यता समाप्त करने के लिए कर सकते हैं (आपके मामले में की तरह: 1 एक) । आपके पास हमेशा एक अवलोकन योग्य नहीं होता है जो केवल एक मान उत्पन्न करने के लिए जाना जाता है।

समस्या यह है कि आप सदस्यता लेने के बाद ही IDisposable प्राप्त करते हैं। एक पर्यवेक्षक आपको OnNext पर वापस कॉल कर सकता है इससे पहले कि यह आपको IDisposable सदस्यता समाप्त करने के लिए वापस लौटाए (IScheduler जैसी चीजों के आधार पर)।

System.Reactive.Disposables.SingleAssignmentDisposable इस मामले में काम में आता है। यह IDisposable को लपेटता है जिसे आप देर से असाइन कर सकते हैं, और SingleAssignmentDisposable को पहले से ही निपटान कर दिया गया है, तो इसे तुरंत असाइनमेंट पर निपटान कर देगा। इसके अलावा इसमें एक संपत्ति IsDisposed है जो प्रारंभ में false है और true पर सेट है जब Dispose() कहा जाता है।

तो:

IObservable<string> source = ...; 

var subscription = new SingleAssignmentDisposable(); 
subscription.Disposable = source.Subscribe(x => 
{ 
    if (subscription.IsDisposed) // getting notified though I've told it to stop 
     return; 
    DoThingsWithItem(x); 
    if (x == "the last item I'm interested in") 
     subscription.Dispose(); 
}); 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^