.NET Reactive Extensions에서 주제가 권장되지 않는 이유는 무엇입니까?


111

저는 현재 .NET 용 Reactive Extensions 프레임 워크를 이해하고 있으며 제가 찾은 다양한 소개 리소스 (주로 http://www.introtorx.com )를 통해 작업하고 있습니다.

우리의 응용 프로그램에는 네트워크 프레임을 감지하는 여러 하드웨어 인터페이스가 포함됩니다. 이러한 인터페이스는 내 IObservable이됩니다. 그런 다음 이러한 프레임을 사용하거나 데이터에 대해 어떤 방식으로 변환을 수행하고 새로운 유형의 프레임을 생성하는 다양한 구성 요소를 갖게됩니다. 예를 들어 매 n 번째 프레임을 표시해야하는 다른 구성 요소도 있습니다. Rx가 우리 애플리케이션에 유용 할 것이라고 확신하지만 IObserver 인터페이스에 대한 구현 세부 사항에 어려움을 겪고 있습니다.

내가 읽은 대부분의 (모두는 아니지만) 리소스는 IObservable 인터페이스를 직접 구현하지 말고 제공된 함수 또는 클래스 중 하나를 사용해야한다고 말했습니다. 내 연구에 따르면를 생성하면 필요한 Subject<IBaseFrame>것을 제공 할 수 있는 것으로 나타났습니다 . 하드웨어 인터페이스에서 데이터를 읽은 다음 Subject<IBaseFrame>인스턴스 의 OnNext 함수를 호출하는 단일 스레드를 갖게 됩니다. 그러면 다른 IObserver 구성 요소가 해당 주제로부터 알림을받습니다.

내 혼란은 이 튜토리얼 의 부록에있는 조언에서 비롯됩니다 .

주제 유형을 사용하지 마십시오. Rx는 효과적으로 함수형 프로그래밍 패러다임입니다. 주체를 사용한다는 것은 잠재적으로 변경 될 수있는 상태를 관리하고 있음을 의미합니다. 변경 상태와 비동기 프로그래밍을 동시에 처리하는 것은 제대로하기가 매우 어렵습니다. 또한 많은 연산자 (확장 메서드)는 구독 및 시퀀스의 정확하고 일관된 수명이 유지되도록주의 깊게 작성되었습니다. 주제를 소개 할 때 이것을 깨뜨릴 수 있습니다. 주제를 명시 적으로 사용하는 경우 향후 릴리스에서도 상당한 성능 저하가 발생할 수 있습니다.

내 애플리케이션은 성능이 매우 중요합니다. 프로덕션 코드에 들어가기 전에 Rx 패턴을 사용하여 성능을 테스트 할 것입니다. 그러나 저는 Subject 클래스를 사용하여 Rx ​​프레임 워크의 정신에 위배되는 작업을하고 있으며 프레임 워크의 향후 버전이 성능을 저하시킬 것이라고 걱정합니다.

내가 원하는 일을하는 더 좋은 방법이 있습니까? 관찰자가 있든 없든 하드웨어 폴링 스레드는 지속적으로 실행될 것이므로 (그렇지 않으면 HW 버퍼가 백업 할 것임) 이것은 매우 핫한 시퀀스입니다. 그런 다음 수신 된 프레임을 여러 관찰자에게 전달해야합니다.

어떤 조언이라도 대단히 감사하겠습니다.


1
주제를 이해하는 데 정말 도움이되었고, 응용 프로그램에서 사용하는 방법에 대해 머릿속에서 바로 이해하고 있습니다. 나는 그들이 옳다는 것을 알고 있습니다-저는 매우 푸시 지향적 인 구성 요소의 파이프 라인을 가지고 있으며 GUI에 표시하고 마지막으로 수신 된 프레임을 버퍼링하기 위해 UI 스레드에서 모든 종류의 필터링 및 호출을 수행해야합니다. 등-처음에 제대로하는지 확인하면됩니다!
Anthony

답변:


70

좋아, 우리가 내 독단적 인 방식을 무시하고 "주체가 좋다 / 나쁘다"를 모두 무시한다면. 문제 공간을 살펴 보겠습니다.

나는 당신이 이해해야 할 시스템의 두 가지 스타일 중 하나를 가지고 있다고 확신합니다.

  1. 메시지가 도착하면 시스템이 이벤트 또는 콜백을 발생시킵니다.
  2. 처리 할 메시지가 있는지 확인하려면 시스템을 폴링해야합니다.

옵션 1의 경우 간단합니다. 적절한 FromEvent 메서드로 래핑하면됩니다. 술집에!

옵션 2의 경우 이제이를 폴링하는 방법과이를 효율적으로 수행하는 방법을 고려해야합니다. 또한 가치를 얻었을 때 어떻게 게시합니까?

폴링 전용 스레드가 필요하다고 생각합니다. 다른 코더가 ThreadPool / TaskPool을 망치고 ThreadPool 고갈 상황에 빠지는 것을 원하지 않을 것입니다. 또는 컨텍스트 전환의 번거 로움을 원하지 않습니다. 따라서 자체 스레드가 있다고 가정하면 폴링을 위해 앉아있는 While / Sleep 루프가있을 것입니다. 수표에서 일부 메시지를 찾으면이를 게시합니다. 이 모든 것이 Observable.Create에 완벽하게 들립니다. 이제 취소를 허용하기 위해 Disposable을 반환 할 수 없기 때문에 While 루프를 사용할 수 없습니다. 다행히도 전체 책을 읽었으므로 재귀 스케줄링에 능숙합니다!

나는 이와 같은 것이 효과가있을 것이라고 상상한다. #검증되지 않은

public class MessageListener
{
    private readonly IObservable<IMessage> _messages;
    private readonly IScheduler _scheduler;

    public MessageListener()
    {
        _scheduler = new EventLoopScheduler();

        var messages = ListenToMessages()
                                    .SubscribeOn(_scheduler)
                                    .Publish();

        _messages = messages;
        messages.Connect();
    }

    public IObservable<IMessage> Messages
    {
        get {return _messages;}
    }

    private IObservable<IMessage> ListenToMessages()
    {
        return Observable.Create<IMessage>(o=>
        {
                return _scheduler.Schedule(recurse=>
                {
                    try
                    {           
                        var messages = GetMessages();
                        foreach (var msg in messages)
                        {
                            o.OnNext(msg);
                        }   
                        recurse();
                    }
                    catch (Exception ex)
                    {
                        o.OnError(ex);
                    }                   
                });
        });
    }

    private IEnumerable<IMessage> GetMessages()
    {
         //Do some work here that gets messages from a queue, 
         // file system, database or other system that cant push 
         // new data at us.
         // 
         //This may return an empty result when no new data is found.
    }
}

제가 주제를 정말 좋아하지 않는 이유는 대개 개발자가 문제에 대한 명확한 디자인을 가지고 있지 않은 경우입니다. 주제를 해킹하고 여기저기서 찔러 넣은 다음 WTF에서 지원 개발자가 추측 한 내용이 계속 진행되도록합니다. Create / Generate etc 메서드를 사용하면 시퀀스에 대한 효과를 지역화하는 것입니다. 하나의 방법으로 모든 것을 볼 수 있으며 다른 누구도 불쾌한 부작용을 일으키지 않는다는 것을 알 수 있습니다. 주제 필드가 보이면 이제 사용중인 클래스의 모든 장소를 찾아야합니다. 일부 MFer가 공개적으로 공개하면 모든 베팅이 해제됩니다. 누가이 시퀀스가 ​​사용되는지 알고 있습니다! Async / Concurrency / Rx는 어렵습니다. 부작용과 인과 관계 프로그래밍이 머리를 더 많이 돌리도록 허용하여 더 어렵게 만들 필요가 없습니다.


10
나는 지금이 답변을 읽고 있지만 주제 인터페이스를 노출하는 것을 결코 고려하지 않을 것임을 지적해야한다고 느꼈습니다! 봉인 된 클래스 (IObservable <> 노출) 내에서 IObservable <> 구현을 제공하는 데 사용하고 있습니다. 제목을 노출하는 이유를 확실히 볼 수있는 <> 인터페이스 나쁜 일 ™ 것
안토니

헤이, 두껍게해서 미안하지만 당신의 코드를 정말 이해하지 못합니다. ListenToMessages () 및 GetMessages ()는 무엇을하고 반환합니까?
user10479 2013

1
개인 프로젝트 @jeromerg의 경우 괜찮을 수 있습니다. 그러나 내 경험상 개발자는 WPF, MVVM, 단위 테스트 GUI 디자인으로 어려움을 겪고 Rx를 던지면 상황이 더 복잡해질 수 있습니다. 나는 BehaviourSubject-as-a-property 패턴을 시도했습니다. 그러나 표준 INPC 속성을 사용한 다음 간단한 Extension 메서드를 사용하여이를 IObservable로 변환하면 다른 사용자에게 훨씬 더 적합하다는 것을 알았습니다. 또한 동작 주제에 대해 작업하려면 사용자 지정 WPF 바인딩이 필요합니다. 이제 가난한 팀은 WPF, MVVM, Rx 및 새 프레임 워크도 배워야합니다.
Lee Campbell

2
@LeeCampbell, 코드 예제와 관련하여 일반적인 방법은 MessageListener가 시스템에 의해 구성되고 (어떻게 든 클래스 이름을 등록 할 수 있음) 시스템이 OnCreate ()를 호출하고 OnGoodbye (), 메시지가 생성되면 message1 (), message2 () 및 message3 ()을 호출합니다. messageX [123]이 주제에 대해 OnNext를 호출하는 것처럼 보이지만 더 좋은 방법이 있습니까?
제임스 무어

1
@JamesMoore는 구체적인 예제로 설명하기가 훨씬 쉽습니다. Rx 및 Subjects를 사용하는 오픈 소스 Android 앱을 알고 있다면 더 나은 방법을 제공 할 수 있는지 시간을 찾을 수있을 것입니다. 나는 받침대에 서서 주제가 나쁘다고 말하는 것이별로 도움이되지 않는다는 것을 이해합니다. 그러나 IntroToRx, RxCookbook 및 ReactiveTrader와 같은 것들은 모두 Rx 사용 방법에 대한 다양한 수준의 예를 제공한다고 생각합니다.
Lee Campbell

38

일반적으로를 사용하지 않는 Subject것이 좋지만 여기서하는 일에 대해서는 꽤 잘 작동한다고 생각합니다. 내가 물어 비슷한 질문을 내가 수신 튜토리얼에서 "회피 대상"메시지를 가로 질러 왔을 때.

Dave Sexton (Rxx의) 을 인용하려면

"대상은 Rx의 상태 저장 구성 요소입니다. 필드 또는 지역 변수로 이벤트와 같은 관찰 가능 항목을 만들어야 할 때 유용합니다."

나는 그것들을 Rx의 진입 점으로 사용하는 경향이 있습니다. 내가 요구 (당신이 가지고있는 것처럼) '뭔가 일이'말을 몇 가지 코드가 그렇다면, 내가 사용하는 것이 Subject및 전화를 OnNext. 그런 다음 IObservable다른 사람들이 구독 할 수 있도록 노출합니다 ( AsObservable()주제에 사용 하여 아무도 주제에 캐스팅하여 일을 엉망으로 만들 수 없도록 할 수 있습니다).

또한 .NET 이벤트 및 사용에이를 수있는 FromEventPattern,하지만 난 단지에 이벤트를 설정하는거야 경우 IObservable어쨌든, 나는 대신의 이벤트가있는의 혜택을 볼 수 없습니다 Subject내가 부족 의미 할 수 있습니다 ( 여기에 뭔가)

그러나, 당신이 아주 강하게 피해야 할 것은 IObservablewith a를 구독하는 것 입니다. SubjectSubject, IObservable.Subscribe메소드에 a 를 전달하지 마십시오 .


왜 상태가 필요합니까? 내 대답에서 알 수 있듯이 문제를 별도의 조각으로 나누면 실제로 상태를 전혀 관리 할 필요가 없습니다. 이 경우 주제를 사용 하면 안됩니다 .
casperOne 2013-01-22

8
@casperOne Subject <T> 또는 이벤트 (둘 다 호출 할 사물 모음, 관찰자 ​​또는 이벤트 처리기) 외부의 상태는 필요하지 않습니다. 이벤트를 추가하는 유일한 이유가 FromEventPattern으로 래핑하는 것이라면 Subject를 사용하는 것을 선호합니다. 당신에게 중요 할 수있는 예외 회로도의 변경을 제외하고는 이런 식으로 주제를 피하는 것이 이점을 보지 못합니다. 다시 말하지만, 주제보다 더 나은 이벤트가 여기에 누락되었을 수 있습니다. 상태에 대한 언급은 인용문의 일부일 뿐이며 그대로 두는 것이 더 나은 것 같았습니다. 그 부분이 없으면 더 명확할까요?
Wilka 2013 년

@casperOne-하지만 FromEventPattern으로 래핑하기 위해 이벤트를 생성해서는 안됩니다. 그것은 분명히 끔찍한 생각입니다.
James Moore

3
블로그 게시물 에서 내 인용문에 대해 더 자세히 설명 했습니다 .
Dave Sexton

나는 그것들을 Rx의 진입 점으로 사용하는 경향이 있습니다. 이것은 나를 위해 머리에 못을 박았다. 호출시 반응 처리 파이프 라인을 통과하려는 이벤트를 생성하는 API가있는 상황이 있습니다. FromEventPattern이 RxJava AFAICT에 존재하지 않는 것 같기 때문에 주제가 저에게 답이었습니다.
scorpiodawg jul.

31

종종 주제를 관리 할 때 실제로 이미 Rx에있는 기능을 다시 구현하고 있으며 강력하고 간단하며 확장 할 수있는 방식은 아닙니다.

일부 비동기 데이터 흐름을 Rx로 조정 (또는 현재 비동기가 아닌 데이터 흐름에서 비동기 데이터 흐름 생성)하려는 경우 가장 일반적인 경우는 다음과 같습니다.

  • 데이터 소스는 이벤트입니다 . Lee가 말했듯이 이것이 가장 간단한 경우입니다. FromEvent를 사용하고 펍으로 향합니다.

  • 데이터 소스는 동기식 작업에서 가져오고 폴링 된 업데이트를 원합니다 (예 : 웹 서비스 또는 데이터베이스 호출) :이 경우 Lee의 제안 된 접근 방식을 사용할 수 있으며 간단한 경우에는 Observable.Interval.Select(_ => <db fetch>). DistinctUntilChanged ()를 사용하여 소스 데이터가 변경되지 않은 경우 업데이트 게시를 방지 할 수 있습니다.

  • 데이터 소스는 콜백을 호출하는 일종의 비동기 API입니다 .이 경우 Observable.Create를 사용하여 콜백을 연결하여 관찰자에서 OnNext / OnError / OnComplete를 호출합니다.

  • 데이터 소스는 새 데이터를 사용할 수있을 때까지 차단하는 호출입니다 (예 : 일부 동기 소켓 읽기 작업) :이 경우 Observable.Create를 사용하여 소켓에서 읽고 Observer에 게시하는 명령형 코드를 래핑 할 수 있습니다. 데이터를 읽을 때. 이것은 당신이 주제로하는 일과 유사 할 수 있습니다.

Observable.Create를 사용하는 것과 Subject를 관리하는 클래스를 만드는 것은 yield 키워드를 사용하는 것과 IEnumerator를 구현하는 전체 클래스를 만드는 것과 상당히 동일합니다. 물론 IEnumerator는 yield 코드만큼 깔끔하고 좋은 시민이되도록 작성할 수 있지만 어느 것이 더 잘 캡슐화되고 깔끔한 디자인을 느끼는가? Observable.Create vs. Subject도 마찬가지입니다.

Observable.Create는 게으른 설정과 깨끗한 분해를위한 깨끗한 패턴을 제공합니다. 주제를 래핑하는 클래스로 어떻게 이것을 달성합니까? 어떤 종류의 Start 메서드가 필요합니다. 언제 호출해야하는지 어떻게 알 수 있습니까? 아니면 아무도 듣지 않을 때도 항상 시작합니까? 완료되면 소켓에서 읽기 / 데이터베이스 폴링 등을 중지하려면 어떻게해야합니까? 어떤 종류의 Stop 메서드가 있어야하며 구독중인 IObservable뿐만 아니라 처음에 Subject를 만든 클래스에 대한 액세스 권한이 있어야합니다.

Observable.Create를 사용하면 모든 것이 한곳에 정리됩니다. Observable.Create의 본문은 누군가 구독 할 때까지 실행되지 않으므로 아무도 구독하지 않으면 리소스를 사용하지 않습니다. 그리고 Observable.Create는 리소스 / 콜백 등을 완전히 종료 할 수있는 Disposable을 반환합니다. 이것은 Observer가 구독을 취소 할 때 호출됩니다. Observable을 생성하는 데 사용하는 리소스의 수명은 Observable 자체의 수명과 깔끔하게 연결됩니다.


1
Observable.Create에 대한 매우 명확한 설명. 감사합니다!
Evan Moran

1
여전히 주체를 사용하는 경우가 있는데, 브로커 객체가 관찰 대상을 노출하는 경우입니다 (예 : 변경 가능한 속성). 다른 구성 요소는 해당 속성이 변경되면 (메서드 호출을 통해) 브로커를 호출하고 해당 메서드는 OnNext를 수행합니다. 소비자가 구독합니다. 이 경우에는 BehaviorSubject를 사용할 것이라고 생각합니다. 그게 적절합니까?
Frank Schwieterman 2016 년

1
상황에 따라 다릅니다. 좋은 Rx 설계는 시스템을 비동기 / 반응 형 아키텍처로 변환하는 경향이 있습니다. 반응 형 코드의 작은 구성 요소를 명령형 디자인의 시스템과 깔끔하게 통합하는 것은 어려울 수 있습니다. 밴드 보조 솔루션은 Subjects를 사용하여 명령형 작업 (함수 호출, 속성 집합)을 관찰 가능한 이벤트로 바꾸는 것입니다. 그러면 반응 코드가 거의없고 실제 "아하!"가 없습니다. 순간. 데이터 흐름을 모델링하고 이에 반응하도록 설계를 변경하면 일반적으로 더 나은 설계가 제공되지만, 만연한 변경이며 사고 방식 전환과 팀 동의가 필요합니다.
Niall Connaughton

1
나는 여기에 (Rx가 경험이없는 것처럼) 다음과 같이 말할 것입니다. Subjects를 사용함으로써 당신은 성장 된 명령형 애플리케이션 내에서 Rx의 세계에 들어가서 천천히 변형시킬 수 있습니다. 또한 첫 경험을 얻으려면 .... 나중에 코드를 처음부터 어떻게해야하는지 확실히 변경하십시오 (웃음). 그러나 우선 주제를 사용하는 것이 가치가 있다고 생각합니다.
Robetto

9

인용 된 블록 텍스트는 왜를 사용하지 말아야하는지 설명 Subject<T>하지만 더 간단하게 말하면 옵저버와 옵저버 블의 기능을 결합하고 그 사이에 일종의 상태를 주입합니다 (캡슐화 또는 확장 여부에 관계없이).

여기서 문제가 발생합니다. 이러한 책임은 서로 분리되고 구별되어야합니다.

즉, 특정 경우에는 우려 사항을 작은 부분으로 나누는 것이 좋습니다.

첫째, 스레드가 뜨겁고 알림을 발생시킬 신호가 있는지 항상 하드웨어를 모니터링합니다. 일반적으로 어떻게 하시겠습니까? 이벤트 . 그래서 그것부터 시작합시다.

EventArgs이벤트가 발생 하는 것을 정의합시다 .

// The event args that has the information.
public class BaseFrameEventArgs : EventArgs
{
    public BaseFrameEventArgs(IBaseFrame baseFrame)
    {
        // Validate parameters.
        if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");

        // Set values.
        BaseFrame = baseFrame;
    }

    // Poor man's immutability.
    public IBaseFrame BaseFrame { get; private set; }
}

이제 이벤트를 발생시킬 클래스입니다. (당신은 항상 스레드가 하드웨어 버퍼를 모니터링 실행이 있기 때문에) 주,이 정적 클래스가 될 수도 있고, 어떤 당신은 온 디맨드에 가입 전화 . 적절하게 수정해야합니다.

public class BaseFrameMonitor
{
    // You want to make this access thread safe
    public event EventHandler<BaseFrameEventArgs> HardwareEvent;

    public BaseFrameMonitor()
    {
        // Create/subscribe to your thread that
        // drains hardware signals.
    }
}

이제 이벤트를 노출하는 클래스가 있습니다. Observable은 이벤트와 잘 작동합니다. 클래스 IObservable<T>정적 FromEventPattern메소드 를 통해 표준 이벤트 패턴을 따르는 경우 이벤트 스트림 (이벤트 스트림을 이벤트의 다중 발생으로 생각)을 구현 으로 변환 하는 Observable일급 지원이 있습니다.

이벤트의 소스와 FromEventPattern메서드를 사용하여 다음과 같이 IObservable<EventPattern<BaseFrameEventArgs>>쉽게 만들 수 있습니다 ( EventPattern<TEventArgs>클래스 는 .NET 이벤트에서 볼 수있는 내용, 특히 EventArgs보낸 사람을 나타내는 개체와 파생 된 인스턴스 를 구현합니다).

// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();

// Create the observable.  It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
    FromEventPattern<BaseFrameEventArgs>(
        h => source.HardwareEvent += h,
        h => source.HardwareEvent -= h);

물론, 당신은 원하는 IObservable<IBaseFrame>, 그러나 그것은 사용하여 쉽게 Select확장 메서드를Observable(당신이 LINQ에서와 같이, 우리가 사용하기 쉬운 방법이 최대의 모든 포장 할 수 있습니다) 투사를 만들 클래스 :

public IObservable<IBaseFrame> CreateHardwareObservable()
{
    // The event source.
    // Or you might not need this if your class is static and exposes
    // the event as a static event.
    var source = new BaseFrameMonitor();

    // Create the observable.  It's going to be hot
    // as the events are hot.
    IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
        FromEventPattern<BaseFrameEventArgs>(
            h => source.HardwareEvent += h,
            h => source.HardwareEvent -= h);

    // Return the observable, but projected.
    return observable.Select(i => i.EventArgs.BaseFrame);
}

7
@casperOne에 대한 귀하의 응답에 감사드립니다. 이것은 제 초기 접근 방식 이었지만 이벤트를 추가하는 것이 "잘못된"느낌이 들었 기 때문에 Rx로 래핑 할 수있었습니다. 현재 구성을로드하고 저장하는 데 사용되는 코드에 맞추기 위해 대리자를 사용합니다 (예, 이벤트가 정확히 무엇인지 알고 있습니다!). 구성 요소 파이프 라인을 다시 빌드 할 수 있어야하며 대리자 시스템이 가장 많이 제공했습니다. 적응성. Rx는 지금이 분야에서 골칫거리지만 프레임 워크의 다른 모든 것의 힘은 구성 문제를 매우 가치있게 해결하는 것입니다.
Anthony

@Anthony 그의 코드 샘플이 작동하도록 할 수 있다면 훌륭하지만 제가 언급했듯이 말이되지 않습니다. "틀렸다"는 느낌에 관해서는 논리적 부분으로 세분화하는 것이 왜 "잘못된"것처럼 보이는지 모르겠지만 원본 게시물에서이를 어떻게 가장 잘 번역 IObservable<T>할 수 있는지에 대한 정보가없는 것으로 표시하기에 충분한 세부 정보를 제공하지 않았습니다. 현재 그 정보로 신호를 보냅니다.
casperOne 2013-01-22

@casperOne 귀하의 의견으로는 주제 사용이 메시지 버스 / 이벤트 어 그리 게이터에 적합합니까?
kitsune 2013 년

1
@kitsune 아니요, 왜 그런지 모르겠습니다. "최적화"를 생각하고 있다면 그게 문제인지 아닌지 질문해야합니다. Rx를 문제의 원인으로 측정 했습니까?
casperOne 2013 년

2
나는 여기서 casperOne과 함께 우려를 나누는 것이 좋은 생각이라는 데 동의합니다. Hardware to Event to Rx 패턴을 사용하면 오류 의미가 손실된다는 점을 지적하고 싶습니다. 손실 된 연결 또는 세션 등은 소비자에게 노출되지 않습니다. 이제 소비자는 재시도, 연결 해제, 다른 시퀀스 또는 다른 항목에 가입할지 여부를 결정할 수 없습니다.
Lee Campbell

0

주제가 공용 인터페이스에 사용하기에 좋지 않다는 것을 일반화하는 것은 좋지 않습니다. 확실히 사실이지만, 이것이 리 액티브 프로그래밍 접근 방식이 아니라는 것은 확실하지만 클래식 코드를위한 좋은 개선 / 리팩토링 옵션입니다.

public set 접근자가있는 일반 속성이 있고 변경 사항에 대해 알리려는 경우 BehaviorSubject로 대체하는 것에 대해 아무 말도하지 않습니다. INPC 또는 기타 다른 이벤트는 그다지 깨끗하지 않으며 개인적으로 나를 지치게합니다. 이를 위해 일반 속성 대신 공용 속성으로 BehaviorSubjects를 사용하고 INPC 또는 기타 이벤트를 버릴 수 있습니다.

또한 주제 인터페이스는 인터페이스의 사용자가 속성의 기능에 대해 더 잘 알 수있게하고 단순히 가치를 얻는 대신 구독 할 가능성이 더 높습니다.

다른 사람이 속성의 변경 사항을 듣거나 구독하도록하려면 사용하는 것이 가장 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.