RX에 가장 적합하다고 생각되는 레거시 이벤트 기반 객체가 있습니다. 네트워크 소스에 연결 한 후 메시지 수신시 이벤트를 발생시키고 단일 오류로 종료 될 수 있습니다 (연결 금형 등) 또는 더 이상 메시지가 없다는 표시 (드물게) 이 객체에는 두 개의 예측이 있습니다. 대부분의 사용자는 수신 된 메시지의 하위 집합에만 관심이 있으므로 잘 알려진 메시지 하위 유형이 나타날 때만 발생하는 대체 이벤트가 있습니다. 이 떨어져 ... 어떻게 든,하지만 ... 느낌이 다른 곳에서 사용되는 방법에 대한IConnectableObservable에서 레거시 객체 래핑
class LegacyReactiveWrapper : IConnectableObservable<TopLevelMessage>
{
private LegacyType _Legacy;
private IConnectableObservable<TopLevelMessage> _Impl;
public LegacyReactiveWrapper(LegacyType t)
{
_Legacy = t;
var observable = Observable.Create<TopLevelMessage>((observer) =>
{
LegacyTopLevelMessageHandler tlmHandler = (sender, tlm) => observer.OnNext(tlm);
LegacyErrorHandler errHandler = (sender, err) => observer.OnError(new ApplicationException(err.Message));
LegacyCompleteHandler doneHandler = (sender) => observer.OnCompleted();
_Legacy.TopLevelMessage += tlmHandler;
_Legacy.Error += errHandler;
_Legacy.Complete += doneHandler;
return Disposable.Create(() =>
{
_Legacy.TopLevelMessage -= tlmHandler;
_Legacy.Error -= errHandler;
_Legacy.Complete -= doneHandler;
});
});
_Impl = observable.Publish();
}
public IDisposable Subscribe(IObserver<TopLevelMessage> observer)
{
return _Impl.RefCount().Subscribe(observer);
}
public IDisposable Connect()
{
_Legacy.ConnectToMessageSource();
return Disposable.Create(() => _Legacy.DisconnectFromMessageSource());
}
public IObservable<SubMessageA> MessageA
{
get
{
// This is the moral equivalent of the projection behavior
// that already exists in the legacy type. We don't hook
// the LegacyType.MessageA event directly.
return _Impl.RefCount()
.Where((tlm) => tlm.MessageType == MessageType.MessageA)
.Select((tlm) => tlm.SubMessageA);
}
}
public IObservable<SubMessageB> MessageB
{
get
{
return _Impl.RefCount()
.Where((tlm) => tlm.MessageType == MessageType.MessageB)
.Select((tlm) => tlm.SubMessageB);
}
}
}
뭔가 :
그래서, 반응 프로그램에 대한 자세한 내용을 학습하는 과정에서, 나는 다음과 같은 래퍼를 만들었습니다. 작동하지만 이상하게 느껴지는 샘플 사용법은 다음과 같습니다. 내 테스트 응용 프로그램의 UI 컨텍스트는 WinForms이지만 실제로 중요하지는 않습니다.// in Program.Main...
MainForm frm = new MainForm();
// Updates the UI based on a stream of SubMessageA's
IObserver<SubMessageA> uiManager = new MainFormUiManager(frm);
LegacyType lt = new LegacyType();
// ... setup lt...
var w = new LegacyReactiveWrapper(lt);
var uiUpdateSubscription = (from msgA in w.MessageA
where SomeCondition(msgA)
select msgA).ObserveOn(frm).Subscribe(uiManager);
var nonUiSubscription = (from msgB in w.MessageB
where msgB.SubType == MessageBType.SomeSubType
select msgB).Subscribe(
m => Console.WriteLine("Got MsgB: {0}", m),
ex => Console.WriteLine("MsgB error: {0}", ex.Message),
() => Console.WriteLine("MsgB complete")
);
IDisposable unsubscribeAtExit = null;
frm.Load += (sender, e) =>
{
var connectionSubscription = w.Connect();
unsubscribeAtExit = new CompositeDisposable(
uiUpdateSubscription,
nonUiSubscription,
connectionSubscription);
};
frm.FormClosing += (sender, e) =>
{
if(unsubscribeAtExit != null) { unsubscribeAtExit.Dispose(); }
};
Application.Run(frm);
이 작품 - 양식 출시의 UI 업데이트, 내가 그것을 닫을 때 구독 청소 얻을합니다 (LegacyType의 네트워크 연결이 연결되어있는 경우는하지 않을 것이다) 프로세스가 종료됩니다. 엄밀히 말하면, 단지 connectionSubscription
을 처리하면 충분합니다. 그러나 명시적인 Connect
은 나에게 이상하다고 느낀다. RefCount
가 당신을 위해 어떻게해야되기 때문에, 차라리 MessageA
및 MessageB
에 _Impl.RefCount
를 사용하여 명시 적으로 나중에 연결하는 것보다, 내가 대신 this.RefCount
을 사용하고 Load
핸들러에 Subscribe
로 통화를 이동하는 래퍼는 수정했습니다. 다른 문제가있었습니다. 두 번째 구독으로 LegacyReactiveWrapper.Connect
이라는 또 다른 호출이 시작되었습니다. 나는 Publish
/RefCount
뒤에있는 아이디어가 "선입 선출 연결, 최후의 연결을 처리합니다."라고 생각했습니다.
- 나는 근본적으로
Publish
/RefCount
오해 마십시오는 내가 세 가지 질문을 가지고 추측?
- 을 구현하는 데 선호되는 방법은
IObservable<T>.Publish
을 통해 얻은 위임과 관련이 없습니다. 나는IObservable<T>
자신을 구현하기로되어 있지 않다는 것을 알고 있지만,Observable.Create().Publish()
이 제공하는IConnectableObservable<T>
에 연결 논리를 주입하는 방법을 이해하지 못합니다.Connect
은 멱등수입니까? - RX/반응 형 프로그래밍에 익숙한 사람이라면 래퍼 사용법에 대한 샘플을보고 "그게 못 생겼고 고장났다"고 말하는가? 아니면 이상하게 보이지 않을까?
구현 세부 사항으로'Publish(). RefCount()'에 +1. 너무 많은 시간이 지나면 기본적으로이 작업을 수행하지 않는 이벤트 래퍼가 표시됩니다. Rx가 구독을 관리하고 있으므로 중복 이벤트 처리기를 기존 이벤트에 추가하여 중복되지 않도록하십시오! :) –