2017-01-17 2 views
0

메서드에 호출하는 일부 데이터를 웹 서비스에 연결하려고 생각합니다.직선 메서드를 사용하여 관찰 가능 객체 만들기

문제 :이 원격 수집 정보에 따라 레이블 컨트롤의 내용 텍스트를 업데이트해야한다고 상상해보십시오. 이 모든 데이터가 다시 수집 될 때까지는 레이블을 표시 할 수 없습니다.

원하는 내용 : 기본 텍스트로 라벨을 먼저 표시하고 싶습니다.이 정보를 수신함에 따라 라벨 내용을 업데이트하고 싶습니다. (제발,이 설명을 흡입 코드로 사용하지 마십시오. , 나는 나의 실제 상황을 간략하게하려고 노력하고있다).

나는이 방법의 관찰 가능한 순서를 만들고 싶습니다. 그럼에도 불구하고이 방법은 동일한 서명이 아닙니다. 예를 들어 :

int GetInt() { 
    return service.GetInt(); 
} 

string GetString() { 
    return service.GetString(); 
} 

string GetString2 { 
    return service.GetString2(); 
} 

이러한 방법은 async는 없습니다.

  1. 관찰 가능한 순서를 만들 수 있습니까?

  2. 어떻게 만들 수 있습니까?

  3. 그럼에도 불구하고, 내 목표를 달성하는 가장 좋은 방법은 무엇입니까?

+0

서비스가 인터페이스 (즉, 'IService')를 지원합니까? – Enigmativity

+0

예. 어떤 아이디어? – Jordi

답변

1

서비스에 대한 래퍼 클래스를 만들어서 값을 별도의 관찰 가능 항목으로 표시하는 방법을 살펴 보겠습니다.

그래서, 서비스 인터페이스로 시작 :

public interface IService 
{ 
    int GetInt(); 
    string GetString(); 
    string GetString2(); 
} 

을 ...다음은 ServiceWrapper 쓰기 :

public class ServiceWrapper : IService 
{ 
    private IService service; 
    private Subject<int> subjectGetInt = new Subject<int>(); 
    private Subject<string> subjectGetString = new Subject<string>(); 
    private Subject<string> subjectGetString2 = new Subject<string>(); 

    public ServiceWrapper(IService service) 
    { 
     this.service = service; 
    } 

    public int GetInt() 
    { 
     var value = service.GetInt(); 
     this.subjectGetInt.OnNext(value); 
     return value; 
    } 

    public IObservable<int> GetInts() 
    { 
     return this.subjectGetInt.AsObservable(); 
    } 

    public string GetString() 
    { 
     var value = service.GetString(); 
     this.subjectGetString.OnNext(value); 
     return value; 
    } 

    public IObservable<string> GetStrings() 
    { 
     return this.subjectGetString.AsObservable(); 
    } 

    public string GetString2() 
    { 
     var value = service.GetString2(); 
     this.subjectGetString2.OnNext(value); 
     return value; 
    } 

    public IObservable<string> GetString2s() 
    { 
     return this.subjectGetString2.AsObservable(); 
    } 
} 

을 이제 현재 서비스가 Service라고 가정, 당신은 일을 설정하려면이 코드를 작성합니다

IService service = new Service(); 
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService` 

var subscription = 
    Observable 
     .Merge(
      wrapped.GetInts().Select(x => x.ToString()), 
      wrapped.GetStrings(), 
      wrapped.GetString2s()) 
     .Subscribe(x => label.Text = x); 

IService wrappedService = wrapped; 

이제 코드에 servicewrappedService을 통과하는 대신 . 여전히 기본이되는 service 코드이므로 다시 쓸 필요는 없습니다. 그러나 여전히 원하는 관찰 대상을 얻고 있습니다.

이것은 실제로 4 개의 갱인 decorator pattern입니다.

+0

정말 대단해! – Jordi

+0

[Many] (http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx) [would] (https://social.msdn.microsoft.com)/Forums/ko-ko/bbf87eea-6a17-4920-96d7-2131e397a234/why-does-emeijer-not-like-subjects) [의견] (http://stackoverflow.com/questions/14396449/why-are-subjects 이 방법으로 주제를 사용하면 많은 불필요한 상태와 오버 헤드가 발생합니다. – ibebbs

+0

@Enigmativity - 코드의 첫 번째 줄이'''IService service = new Service()''를 읽는 것으로 가정합니다. 그렇지 않으면'''wrappedService'' 소비자는 any를 호출 할 때 null 참조 예외를받습니다. GetXXX 메서드 중 무엇입니까? – ibebbs

2

Observable.Create으로 사용자 정의 관찰 가능 시퀀스를 생성 할 수 있습니다. 귀하의 요구 사항을 사용하는 예는 다음과 같습니다 : 나는 getXXX 메소드의 각으로 Thread.Sleep 전화를 도입함으로써 네트워크 지연을 모방 얼마나

private int GetInt() 
{ 
    Thread.Sleep(1000); 

    return 1; 
} 

private string GetString() 
{ 
    Thread.Sleep(1000); 

    return "Hello"; 
} 

private string GetString2() 
{ 
    Thread.Sleep(2000); 

    return "World!"; 
} 

private IObservable<string> RetrieveContent() 
{ 
    return Observable.Create<string>(
     observer => 
     { 
      observer.OnNext("Default Text"); 

      int value = GetInt(); 

      observer.OnNext($"Got value {value}. Getting string..."); 

      string string1 = GetString(); 

      observer.OnNext($"Got string {string1}. Getting second string..."); 

      string string2 = GetString2(); 

      observer.OnNext(string2); 
      observer.OnCompleted(); 

      return Disposable.Empty; 
     } 
    ); 
} 

참고. 당신이로 가입해야합니다,이 관측에 가입 할 때 UI가 응답하지 않도록하기 위하여 다음과

IDisposable subscription = RetrieveContent() 
    .SubscribeOn(TaskPoolScheduler.Default) 
    .ObserveOn(DispatcherScheduler.Current) 
    .Subscribe(text => Label = text); 

이 코드는 관찰 순서를 시작하는 TaskPool을 스레드를 사용하는 .SubscribeOn(TaskPoolScheduler.Default) 확장 방법을 사용하고 차단됩니다 Thread.Sleep을 호출하지만 UI 스레드가 아니기 때문에 UI는 응답 성이 유지됩니다. 그런 다음 UI 스레드에서 UI를 업데이트하기 위해 (데이터 바인딩 된) Label 속성을 설정하기 전에 ".ObserveOn (DispatcherScheduler.Current)"을 사용하여 UI 스레드에 업데이트를 호출합니다.

희망 사항이 당신이 찾고있는 것이지만, 의견이 있으면 남겨 두어 더 도움을 드리겠습니다.

+0

"Disposable.Empty;를 반환 할 때마다이를 고려해야합니다. 잘못된 것을하고있을 것입니다. – Enigmativity

+0

'System.InvalidOperationException' 예외가 발생했습니다 :'현재 쓰레드는 연관된 Dispatcher가 없습니다 .' 스택 추적의 마지막 줄은'System.Reactive.Concurrency.DispatcherScheduler.get_Current()'에 있습니다. 나는 그것을 어떻게 다루는지를 잘 모르고있다. 어떤 아이디어? – Jordi

+0

@Enigmativity - 여기에 의견을 올려주세요. "반드시 Disposable.Empty를 반환 할 때 언제든지 잘못된 것을하고 있습니다."라고 동의하는 것은 아니지만 구독 취소시 (즉 취소를 수행 할 때) 몇 가지 추가 동작을 수행할지 여부를 고려해 볼 가치가 있습니다. . 그러나 이것은 OP가 요청하지 않았으므로 간략하게 생략했습니다. – ibebbs

관련 문제