本文主要描述使用Rx對當(dāng)前使用.net事件模型和異步編程的好處。
無論是你處理傳統(tǒng)的桌面程序還是基于Web的應(yīng)用程序,你都必須時不時地處理異步編程。桌面程序的I/O操作或者UI線程,可能需要很長時間才能完成,而在完成過程中可能阻塞其他的線程。Silverlight禁止任何阻塞線程的調(diào)用,你唯一可以做的就是使用異步編程。 然而,現(xiàn)代異步編程模型的用戶必須手動管理事件的異常和取消。 要編寫或過濾事件,他必須編寫難以閱讀和維護(hù)的自定義代碼。
此外,如果您的應(yīng)用程序與多個數(shù)據(jù)源交互,管理所有這些交互的常規(guī)方法是對每個數(shù)據(jù)流實現(xiàn)單獨的方法作為事件處理程序。 例如,一旦用戶鍵入一個字符,keydown事件就被推送到您的keydown事件處理程序方法。 在這個keydown事件處理程序中,你必須提供代碼來響應(yīng)這個事件,或者協(xié)調(diào)所有不同的數(shù)據(jù)流,并將這些數(shù)據(jù)處理成可用的形式。 如果您要訂閱某個事件,您首先創(chuàng)建一個事件處理程序,然后您可以按照以下代碼訂閱該事件。
public event EventHandler<MouseEventArgs> MouseMove;/// Publish dataMouseMove(this, args);///Subscribe to an eventMouseMove += (sender, args) => Display(args)使用Rx,您可以表示多個異步數(shù)據(jù)流(來自不同來源,例如股票報價,tweet,計算機(jī)事件,Web服務(wù)請求等),并使用IObserver<T>界面訂閱事件流。 IObservable 接口維護(hù)從屬IObserver 接口的列表,并自動通知它們?nèi)魏螤顟B(tài)變化。 您可以使用由Observable類型實現(xiàn)的標(biāo)準(zhǔn)LINQ查詢運算符查詢可觀察序列。 因此,您可以通過使用這些靜態(tài)LINQ運算符,輕松地對多個事件進(jìn)行過濾,項目,聚合,組合和執(zhí)行基于時間的操作。 還可以通過使用由Rx提供的擴(kuò)展方法來優(yōu)雅地處理取消和異常。 以下示例創(chuàng)建一個表示事件流的ISubject實例(它繼承了IObservable和IObserver)。 然后它使用相同的對象發(fā)布數(shù)據(jù)和接收訂閱。 有關(guān)使用主題的更多信息,請參閱使用主題。
///Declare an observablepublic ISubject<MouseEventArgs> MouseMove;///Publish dataMouseMove.OnNext(args);///Subscribe to an observableMouseMove.Subscribe(args => Display(args));您還可以使用調(diào)度程序來控制訂閱何時開始,以及何時將通知推送到訂閱者。 有關(guān)此的詳細(xì)信息,請參閱使用計劃程序。
基于.NET事件的模型的一個缺點是,每當(dāng)一個事件被觸發(fā)時,事件處理程序總是被調(diào)用,并且事件完全按照源發(fā)出的方式到達(dá)。 要過濾掉您不感興趣的事件或在調(diào)用處理程序之前轉(zhuǎn)換數(shù)據(jù),您必須向處理程序添加自定義過濾器邏輯。 以檢測鼠標(biāo)按下的應(yīng)用程序為例。在當(dāng)前事件編程模型中,您必須編寫一個事件處理程序,將MouseEventArgs作為參數(shù)。應(yīng)用程序可以通過顯示消息來響應(yīng)所引發(fā)的事件。在Rx中,此類鼠標(biāo)按下事件被視為點擊信息流。每當(dāng)您點擊鼠標(biāo)時,關(guān)于此點擊的信息(例如,光標(biāo)位置)就會顯示在流中,隨時可以處理。在這個范例中,事件(或事件流)非常類似于列表或其他集合。這意味著我們可以使用處理集合的技術(shù)來處理事件。例如,您可以過濾出現(xiàn)在特定區(qū)域之外的點擊,并且只有在用戶點擊某個區(qū)域時才顯示一條消息。或者,您可以等待特定時間段,并通知用戶此期間的“有效”點擊次數(shù)。類似地,您可以捕獲股票行情,并僅響應(yīng)在特定時間窗口內(nèi)針對特定范圍更改的那些行情。所有這些都可以通過使用由Rx提供的靜態(tài)LINQ查詢類型運算符來輕松完成。 這樣,函數(shù)可以獲取事件,處理它,然后將處理的流傳遞給應(yīng)用程序。 這提供了當(dāng)前編程模型中不可用的靈活性。 此外,由于Rx在后臺執(zhí)行所有管道工作以過濾,同步和轉(zhuǎn)換數(shù)據(jù),因此您的處理程序只能對接收的數(shù)據(jù)做出反應(yīng),并對其進(jìn)行處理。 這導(dǎo)致更干凈的代碼更容易閱讀和維護(hù)。 有關(guān)過濾的更多信息,請參閱使用LINQ運算符查詢可觀察序列。
在基于.NET事件的模型中,事件無法輕松構(gòu)成。 您不能訂閱多個事件并基于輸出合成結(jié)果。 在Rx的世界中,在組件中實現(xiàn)了諸如SelectMany,Merge等通用LINQ操作符。 這些運算符使您能夠組合多個事件流,以向訂閱者返回有意義的內(nèi)容。 例如,您可以創(chuàng)建一個可觀察的序列,同時監(jiān)聽鼠標(biāo)向下和鼠標(biāo)移動事件。 然后你可以訂閱這個可觀察的序列,這樣你得到的是一個組合的鼠標(biāo)拖動事件。 有關(guān)撰寫的更多信息,請參閱使用LINQ運算符查詢可觀察序列。
在基于.NET事件的模型中,事件是隱藏的數(shù)據(jù)源,不能交給另一個服務(wù),應(yīng)用程序或函數(shù)進(jìn)行存儲或進(jìn)一步處理。 正如我們前面所討論的,Rx將事件表示為對象的集合:例如,MouseMove事件包含Point值的集合。 由于可觀察值的第一類對象性質(zhì),它們可以作為函數(shù)參數(shù)傳遞并返回,或存儲在變量中。
在基于.NET事件的模型中,要停止接收事件的通知,必須顯式取消注冊事件處理程序。 Rx通過允許您指定對數(shù)據(jù)源感興趣的時間長度,使此任務(wù)更簡單。 例如,當(dāng)您訂閱表示事件流的可觀察序列時,您可以指定希望從序列中通知更改的時間長度(例如,n次迭代,或者類似于“在3之間不推”的時間間隔 -5pm“,或當(dāng)其他事件發(fā)生時)。 此外,當(dāng)您訂閱可觀察序列時,您將獲得一個IDisposable句柄,您可以使用該句柄取消訂閱(通過調(diào)用Dispose)到該序列。
新聞熱點
疑難解答