C #의 getter 또는 setter에서 비동기 메서드를 호출하는 가장 우아한 방법은 무엇입니까?
자신을 설명하는 데 도움이되는 의사 코드가 있습니다.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
답변
C #에서 속성을 사용할 수 없는 기술적 이유 async
는 없습니다. “비동기 특성”이 옥시 모론이기 때문에 의도적 인 설계 결정이었습니다.
속성은 현재 값을 반환해야합니다. 백그라운드 작업을 시작해서는 안됩니다.
일반적으로 누군가 “비동기 속성”을 원할 때 실제로 원하는 것은 다음 중 하나입니다.
- 값을 반환하는 비동기 메서드 이 경우 속성을
async
메서드로 변경하십시오 . - 데이터 바인딩에 사용할 수 있지만 비동기 적으로 계산 / 검색해야하는 값입니다. 이 경우
async
포함 객체에 팩토리 메소드를 사용하거나async InitAsync()
메소드를 사용하십시오 . 데이터 바운드 값은default(T)
값을 계산 / 검색 할 때까지입니다. - 작성하는 데 비용이 많이 들지만 나중에 사용하기 위해 캐시해야하는 값입니다. 이 경우
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()
{
//...
}
}
동기화 컨텍스트와 속성 변경 알림을 처리합니다.