[c#] getter 또는 setter에서 비동기 메소드를 호출하는 방법은 무엇입니까?

C #의 getter 또는 setter에서 비동기 메서드를 호출하는 가장 우아한 방법은 무엇입니까?

자신을 설명하는 데 도움이되는 의사 코드가 있습니다.

async Task<IEnumerable> MyAsyncMethod()
{
    return await DoSomethingAsync();
}

public IEnumerable MyList
{
    get
    {
         //call MyAsyncMethod() here
    }
}



답변

C #에서 속성을 사용할 수 없는 기술적 이유 async는 없습니다. “비동기 특성”이 옥시 모론이기 때문에 의도적 인 설계 결정이었습니다.

속성은 현재 값을 반환해야합니다. 백그라운드 작업을 시작해서는 안됩니다.

일반적으로 누군가 “비동기 속성”을 원할 때 실제로 원하는 것은 다음 중 하나입니다.

  1. 값을 반환하는 비동기 메서드 이 경우 속성을 async메서드로 변경하십시오 .
  2. 데이터 바인딩에 사용할 수 있지만 비동기 적으로 계산 / 검색해야하는 값입니다. 이 경우 async포함 객체에 팩토리 메소드를 사용하거나 async InitAsync()메소드를 사용하십시오 . 데이터 바운드 값은 default(T)값을 계산 / 검색 할 때까지입니다.
  3. 작성하는 데 비용이 많이 들지만 나중에 사용하기 위해 캐시해야하는 값입니다. 이 경우 AsyncLazy 내 블로그 또는 AsyncEx 라이브러리에서 사용하십시오 . 이것은 당신에게 await유능한 재산을 줄 것 입니다.

업데이트 : 최근 “async OOP”블로그 게시물 중 하나에서 비동기 속성 을 다룹니다 .


답변

비동기 속성 지원이없고 비동기 메서드 만 있기 때문에 비동기 적으로 호출 할 수 없습니다. 따라서, 두 가지 옵션의 CTP에서 비동기 방법은 정말 방법이 반환 사실을 모두 복용 장점이 있습니다 Task<T>또는 Task:

// Make the property return a Task<T>
public Task<IEnumerable> MyList
{
    get
    {
         // Just call the method
         return MyAsyncMethod();
    }
}

또는:

// Make the property blocking
public IEnumerable MyList
{
    get
    {
         // Block via .Result
         return MyAsyncMethod().Result;
    }
}


답변

필자는 분리 된 아키텍처로 인해 get 메소드에서 시작하는 호출이 필요했습니다. 그래서 다음 구현을 생각해 냈습니다.

사용법 : 제목 은 ViewModel 또는 페이지 리소스로 정적으로 선언 할 수있는 개체에 있습니다. 여기에 바인딩하면 getTitle ()이 반환 될 때 UI를 차단하지 않고 값이 채워집니다.

string _Title;
public string Title
{
    get
    {
        if (_Title == null)
        {
            Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); });
        }
        return _Title;
    }
    set
    {
        if (value != _Title)
        {
            _Title = value;
            RaisePropertyChanged("Title");
        }
    }
}


답변

첫 번째 null을 반환하고 실제 값을 얻는 값을 기다릴 수 있다고 생각하므로 Pure MVVM (예 : PCL 프로젝트)의 경우 다음이 가장 우아한 솔루션이라고 생각합니다.

private IEnumerable myList;
public IEnumerable MyList
{
  get
    {
      if(myList == null)
         InitializeMyList();
      return myList;
     }
  set
     {
        myList = value;
        NotifyPropertyChanged();
     }
}

private async void InitializeMyList()
{
   MyList = await AzureService.GetMyList();
}


답변

다음 Task과 같이 사용할 수 있습니다 :

public int SelectedTab
        {
            get => selected_tab;
            set
            {
                selected_tab = value;

                new Task(async () =>
                {
                    await newTab.ScaleTo(0.8);
                }).Start();
            }
        }


답변

.GetAwaiter (). GetResult () 가이 문제의 해결책이라고 생각했습니다. 예 :

string _Title;
public string Title
{
    get
    {
        if (_Title == null)
        {
            _Title = getTitle().GetAwaiter().GetResult();
        }
        return _Title;
    }
    set
    {
        if (value != _Title)
        {
            _Title = value;
            RaisePropertyChanged("Title");
        }
    }
}


답변

‘비동기 속성’이 뷰 모델에 있으므로 AsyncMVVM을 .

class MyViewModel : AsyncBindableBase
{
    public string Title
    {
        get
        {
            return Property.Get(GetTitleAsync);
        }
    }

    private async Task<string> GetTitleAsync()
    {
        //...
    }
}

동기화 컨텍스트와 속성 변경 알림을 처리합니다.