2016-03-08 37 views
2

Observable.FromEvent有這樣的簽名的目的是什麼? 對於exampleObservable.FromEvent簽名

var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h, 
h => Application.Current.Activated -= h); 

特別是,什麼是h?爲什麼+=,然後-=?我們是否從事件或事件處理程序製作Observable?如果從事件,爲什麼不只是有這樣的簽名:

var appActivated = Observable.FromEvent(Application.Current.Activated); 
+1

我寫了一個很長的解釋和討論的FromEvent一會兒,可能是有用的:http://stackoverflow.com/questions/19895373/how-to-use-observable-fromevent-instead-of-fromeventpattern-and -avoid-string-lit/19896246#19896246 –

+1

@詹姆斯世界:在閱讀答案後,我有60-70%的理解。閱讀你的文章後,它大於95%。特別是您的段落以「注意,這只是調用訂閱創建訂閱的行爲」。幫了我很多。 – Bad

+0

感謝您的反饋。這是一個令人驚訝的深層方法,需要大量的解釋! –

回答

3

Eren的回答是正確的;我想確保您的所有問題都得到解答:

In particular, what is h?

h是代表添加和刪除處理程序的參數。當被調用時,h將是對處理程序委託的引用。

And why +=, then -=?

observable需要能夠同時訂閱和取消訂閱事件。

Do we make Observable from event or from event handler?

從一個事件。

If from event, why not just have a signature like: var appActivated = Observable.FromEvent(Application.Current.Activated); ?

因爲那樣會通過處理程序,而不是事件。 「事件」是三件事情:調用處理程序列表的能力,向列表添加新處理程序的能力以及從列表中移除處理程序的能力。可觀察到的需要最後兩個;你的建議是通過第一個。所以觀察者需要最後兩位的代表。

+1

並且爲了您的最後一點,他[大概]不會從定義該事件的類編寫此代碼,因此即使訪問處理程序列表也是無效的,無法編寫該代碼可以編譯的'FromEvent'方法,更不用說做它需要做的事情了。 – Servy

+0

我其實還是不明白的是:我們有事件,我們想從他們身上製造出一系列事件。所以這裏沒有提到任何處理程序。這個'h'處理程序好像出現並從無處消失。對不起,也許我在概念上不理解。 – Bad

+1

@Bad:你可能不明白lambda是什麼?當你說'customers.Select(c => c.FirstName)''c'只是出現「無處」。你知道lambda只是寫一個方法的一個簡短方法嗎? –

5

這是因爲沒有辦法在事件以作爲參數傳遞給的方法。您可以將該活動作爲代表傳遞,但不能讓您訂閱/取消訂閱該活動。見Eric Lippert的answer

Observable.From基本上說「好吧,我會給你一個可觀察的事件包裝,但你需要爲我提供兩個代表:1)代表我爲我的處理程序訂閱事件,2 )當我需要時,我的一位代表取消訂閱我的處理程序「。

所以在這種情況下,h => Application.Current.Activated += h是一個lambda表達式,它被編譯成一個委託。 h(處理程序)是輸入參數,委託人將該輸入參數並將其歸入Activated事件。第二個委託是同樣的事情,除了取消訂閱處理程序。

2

Observable是.NET中的第一類類型 - 這意味着您可以保留對它們的引用並將它們作爲參數傳遞給您喜歡的任何構造函數/方法。

活動是不是一流的類型。它們只能在可以引用其包含對象的範圍內附加和分離。

因此,這意味着我不能做到這一點:

public void SomeMethod(EventHandler handler) 
    { 
     handler += (s, e) => { /* Handler Code */ }; 
    } 

    public void SomeOtherMethod() 
    { 
     SomeMethod(Application.Current.Activated); 
    } 

如果我嘗試,我得到的錯誤:

The event 'Application.Activated' can only appear on the left hand side of += or -=

這應該讓你知道你爲什麼不能做var appActivated = Observable.FromEvent(Application.Current.Activated);

那麼,我怎樣才能解決這個問題附加SomeMethod事件?

方法如下:

public void SomeMethod(Action<EventHandler> addHandler) 
    { 
     addHandler((s, e) => { /* Handler Code */ }); 
    } 

    public void SomeOtherMethod() 
    { 
     SomeMethod(h => Application.Current.Activated += h); 
    } 

基本上,SomeMethod參數不再EventHandler,但Action<EventHandler>方法。這意味着我不再試圖傳遞事件本身 - 而是傳遞一種方式讓被調用的代碼將自己附加到我的事件中。撥打SomeMethodh承諾如果我將來有一個有效的處理程序,那麼我可以通過調用Action<EventHandler>來附加它。

因此,讓我們說我現在想寫一些代碼,知道如何附加和從事件分離。我現在需要這個代碼:

public void SomeMethod(Action<EventHandler> addHandler, Action<EventHandler> removeHandler) 
    { 
     EventHandler handler = (s, e) => { /* Handler Code */ }; 

     addHandler(handler); 

     /* Some Intervening Code */ 

     removeHandler(handler); 
    } 

    public void SomeOtherMethod() 
    { 
     SomeMethod(h => Application.Current.Activated += h, h => Application.Current.Activated -= h); 
    } 

/* Some Intervening Code */代碼附加處理程序,並且它取出來之後。

這給我們帶來了你的代碼在你的問題:

var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h, 
h => Application.Current.Activated -= h); 

這在很大程度上與上面相同的SomeMethod呼叫 - FromEvent需要爲它附加和從事件分離的方式。 h是一個承諾,說:「嘿,FromEvent,如果你可以提供一個處理程序,當你將來需要它時,我保證這個代碼將正確地附加它。」或者,根據具體情況分離。

現在,只是有點迂腐,你的代碼實際上應該是:

 IObservable<EventPattern<EventArgs>> appActivated = 
      Observable 
       .FromEventPattern<EventHandler, EventArgs>(
        h => Application.Current.Activated += h, 
        h => Application.Current.Activated -= h); 

現在,我有一個IObservable<EventPattern<EventArgs>>我可以重寫SomeMethod藉此作爲參數,並把它寫這樣的:

public IDisposable SomeMethod(IObservable<EventPattern<EventArgs>> appActivated) 
    { 
     return appActivated.Subscribe(ep => { /* Handler Code */ }); 
    } 

現在可以看到Rx的所有功能。 .Subscribe方法不需要任何對原始事件包含對象的引用,但它最終將調用h => Application.Current.Activated += h附加,並在需要時分離。現在,我可以有效地將事件作爲.NET中的第一類類型傳遞。