C#でゲッターまたはセッターから非同期メソッドを呼び出す最もエレガントな方法は何ですか?
以下に、自分自身を説明するための擬似コードを示します。
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
分離されたアーキテクチャのため、getメソッドから発信する呼び出しが本当に必要でした。そこで、次の実装を思いつきました。
使用法:Titleは、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");
}
}
}
async
プロパティがC#で許可されない理由technicalの理由はありません。 「非同期プロパティ」は矛盾した表現なので、意図的な設計決定でした。
プロパティは現在の値を返す必要があります。バックグラウンド操作を開始しないでください。
通常、誰かが「非同期プロパティ」を望んでいるとき、彼らが本当に望んでいるのは次のいずれかです。
async
メソッドに変更します。async
ファクトリーメソッドを使用するか、async InitAsync()
メソッドを使用します。値が計算/取得されるまで、データバインド値はdefault(T)
になります。AsyncLazy
私のブログから または AsyncExライブラリ を使用します。これにより、await
ableプロパティが得られます。更新:最近の「非同期OOP」ブログ投稿の1つで 非同期プロパティ を説明します。
非同期プロパティのサポートはなく、非同期メソッドのみであるため、非同期で呼び出すことはできません。そのため、CTPの非同期メソッドは実際にはTask<T>
またはTask
を返すメソッドにすぎないという事実を利用する2つのオプションがあります。
// 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;
}
}
最初の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();
}
.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()
{
//...
}
}
同期コンテキストとプロパティ変更通知を処理します。
次のようにTask
を使用できます。
public int SelectedTab
{
get => selected_tab;
set
{
selected_tab = value;
new Task(async () =>
{
await newTab.ScaleTo(0.8);
}).Start();
}
}