2017-04-13 48 views
0

所以有可能我最終會遇到以下代碼的幾個問題,也許是因爲我使用了Subject,我不確定它是否可以使用。當我需要選擇許多可觀察對象時,我是否正確思考?

這很難讓我解釋,我不知道爲什麼,也許我缺乏術語。

我想要做的是有一個類型,它可以註冊幾個觀察對象,所以我可以傳遞這個類型,並將所有觀察對象組合在一起,並從中展示一個可觀察對象。

所以我的第一個問題我感覺我沒有以正確的方式思考事情,我想知道這是正確的還是存在一種更「反應性」的方式?

我的意思是,我有這個類型,你可以註冊觀測,也該類型不同,就會暴露出單一可觀察,我也可以訂閱。

我會盡量用下面的代碼示例來解釋一下。 因此,SomeTypeWithObservable可能是多種類型中的一種,它們將公開IObservable<SomeEvents> ReactiveTesting類型是嘗試將所有觀測值組合在一起並暴露單個IObservable<SomEvents>的類型。有一個RegisterObservable方法將發送到內部Subject<IObservable<SomeEvents>>。構造函數將Observable設置爲我想公開的這個主題的SelectMany

使用下面的執行,在ReactiveTesting構造我進行SelectMany.Publish.RefCount,與虛擬訂閱之後,開始觀察到的,我發現,如果我沒有用假認購不使用可觀的註冊。

所以我第二個問題是代碼行有一個虛擬的訂閱開始可觀察到的,或者我應該做的我做了下面的評論,我剛剛從發表一個連接,然後連接後立即,或者他們都是錯誤的,在這種情況下,有人能指出我的方向是正確的嗎?

第三個問題我應該使用一個主題?

如果我打電話RegisterObservable早於訂閱,如果我不把在虛擬SubscribeConnect那麼我不會觀察者觸發任何事件。

四問題有人能解釋一下後者好嗎? 我有種想法,因爲它是PublishRefCount那麼在訂閱以Observable開始之前沒有什麼可做的。

代碼

--Edited - 要顯示有不止一個可觀察我想在ReactiveTesting

enum SomeEvents 
{ 
    event1, 
    event2, 
    event3, 
    event4 
} 

interface ISomeTypeWithObservable 
{ 
    IObservable<SomeEvents> SomeObservableEvents { get; } 
} 

class SomeTypeWithObservable2 : ISomeTypeWithObservable 
{ 
    private event EventHandler SpecialEvent; 
    public SomeTypeWithObservable2() 
    { 
     var observableFromSpecialEvent = Observable.FromEventPattern(h => SpecialEvent += h, h => SpecialEvent -= h).Select(x => SomeEvents.event2); 
     SomeObservableEvents = Observable.Create<SomeEvents>(observer => 
      { 
       return observableFromSpecialEvent.Subscribe(observer); 
      }) 
      .Publish() 
      .RefCount(); 
    } 

    public IObservable<SomeEvents> SomeObservableEvents { get; } 
    public void TriggerEvent() 
    { 
     SpecialEvent.Invoke(this, new EventArgs()); 
    } 
} 

class SomeTypeWithObservable : ISomeTypeWithObservable 
{ 
    private event EventHandler SpecialEvent; 
    public SomeTypeWithObservable() 
    { 
     var observableFromSpecialEvent = Observable.FromEventPattern(h => SpecialEvent += h, h => SpecialEvent -= h).Select(x => SomeEvents.event1); 
     SomeObservableEvents = Observable.Create<SomeEvents>(observer => 
      { 
       return observableFromSpecialEvent.Subscribe(observer); 
      }) 
     .Publish() 
     .RefCount(); 
    } 

    //Some code in here that will produce things to observe, maybe Observable.FromEventPattern... 
    public IObservable<SomeEvents> SomeObservableEvents { get; } 

    public void TriggerEvent() 
    { 
     SpecialEvent.Invoke(this, new EventArgs()); 
    } 
} 

class ReactiveTesting 
{ 
    private Subject<IObservable<SomeEvents>> _innerEvents = new Subject<IObservable<SomeEvents>>(); 

    public IObservable<SomeEvents> AllEvents; 
    public ReactiveTesting() 
    { 
     AllEvents = _innerEvents.SelectMany(x => x).Publish().RefCount(); 
     AllEvents.Subscribe(next => { }, exception => { },() => { }); 

     //This instead of the above?? 
     //var connectableObservable = _innerEvents.SelectMany(x => x).Publish(); 
     //AllEvents = connectableObservable; 
     //connectableObservable.Connect(); 
    } 

    public void RegisterObservable(ISomeTypeWithObservable someTypeWithObservable) 
    { 
     _innerEvents.OnNext(someTypeWithObservable.SomeObservableEvents); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var reactiveTesting = new ReactiveTesting(); 
     var someTypeWithObservable = new SomeTypeWithObservable(); 
     var someTypeWithObservable2 = new SomeTypeWithObservable2(); 
     reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 1 - {0}", next.ToString("G")))); 
     reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 2 - {0}", next.ToString("G")))); 
     reactiveTesting.RegisterObservable(someTypeWithObservable); 
     reactiveTesting.RegisterObservable(someTypeWithObservable2); 
     someTypeWithObservable.TriggerEvent(); 
     someTypeWithObservable.TriggerEvent(); 
     someTypeWithObservable.TriggerEvent(); 
     someTypeWithObservable2.TriggerEvent(); 
     someTypeWithObservable2.TriggerEvent(); 
     someTypeWithObservable2.TriggerEvent(); 

     Console.WriteLine("Press key..."); 
     Console.ReadLine(); 
    } 
} 

回答

0

所以我的第一個問題,我得到一種感覺,我註冊我沒有想到 中的東西是正確的方式,我想知道這是否正確或有更多 「反應」的方式嗎?

一個在ReactiveTestingSubject使用通常是,你有可能被淘汰,或進一步推了一些必要的代碼提示。它可能需要重新編寫一些你周圍的代碼。在這種情況下,你最終會得到這樣的:

class ReactiveTesting 
{ 
    public IObservable<SomeEvents> AllEvents { get; } 
    public ReactiveTesting(IObservable<IObservable<SomeEvents>> eventSource) 
    { 
     AllEvents = eventSource.Merge().Publish().RefCount(); 
    } 
} 
class Program 
{ 
    public static void Main(string[] args) 
    { 
     var someTypeWithObservable = new SomeTypeWithObservable(); 
     var reactiveTesting = new ReactiveTesting(Observable.Return(someTypeWithObservable.SomeObservableEvents)); 
     reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 1 - {0}", next.ToString("G")))); 
     reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 2 - {0}", next.ToString("G")))); 
     someTypeWithObservable.TriggerEvent(); 
     someTypeWithObservable.TriggerEvent(); 
     someTypeWithObservable.TriggerEvent(); 

     Console.WriteLine("Press key..."); 
     Console.ReadLine(); 

    } 
} 

所以我的第二個問題是,代碼可以擁有一個虛擬的訂閱 開始可觀察到的,或者我應該做的我做了下在 評論裏,我剛剛可以從發佈連接,然後立即連接 ,或者他們都是錯誤的,在這種情況下,有人可以指點我正確的方向嗎?

應該沒有必要。它對我的作用與去除它一樣。虛擬訂閱有助於.Replay().Refcount()。我沒有看到.Publish()的觀點。

我的第三個問題我應該使用一個主題嗎?

它們基本上是一種代碼味道。如果你可以消除它們,或者將它們從業務邏輯中推開,那麼你就會變得更好。

+0

非常感謝您的回答:-)我想我可能不清楚我想做什麼。我希望能夠用'ReactiveTesting'來註冊許多觀察對象所以'ReactiveTesting'基本上是一個單例,並且可以將所有這些觀察對象組合起來併產生1個。也許我沒有以正確的方式考慮這個與Rx相關的解決方案。此外,訂閱可能發生在我註冊/合併一個新的observable之前。我以爲我會使用發佈,所以我可以訂閱比註冊晚,並仍觀察相同的觀察。 – RichardWilliams

相關問題