293

C# でゲッターまたはセッターから非同期メソッドを呼び出す最もエレガントな方法は何ですか?

自分自身を説明するのに役立つ疑似コードを次に示します。

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

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

13 に答える 13

281

C# でプロパティが許可されないという技術的な理由はありません。async「非同期プロパティ」は矛盾しているため、意図的な設計上の決定でした。

プロパティは現在の値を返す必要があります。バックグラウンド操作を開始するべきではありません。

通常、「非同期プロパティ」が必要な場合、実際に必要なのは次のいずれかです。

  1. 値を返す非同期メソッド。この場合、プロパティをasyncメソッドに変更します。
  2. データバインディングで使用できる値ですが、非同期で計算/取得する必要があります。この場合、async含まれているオブジェクトのファクトリ メソッドを使用するか、メソッドを使用しasync InitAsync()ます。データバインドさdefault(T)れた値は、値が計算/取得されるまで続きます。
  3. 作成にはコストがかかりますが、将来の使用のためにキャッシュする必要がある値。この場合、AsyncLazy 私のブログまたはAsyncEx ライブラリから使用します。これにより、await有能なプロパティが得られます。

更新:最近の「非同期OOP 」ブログ投稿の 1 つで、非同期プロパティについて説明しています。

于 2012-12-06T01:16:06.217 に答える
119

非同期プロパティはサポートされておらず、非同期メソッドのみがサポートされているため、非同期で呼び出すことはできません。Task<T>そのため、2 つのオプションがあり、どちらも CTP の非同期メソッドは実際にはorを返すメソッドにすぎないという事実を利用しています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;
    }
}
于 2011-07-06T20:16:50.920 に答える
59

アーキテクチャが分離されているため、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");
        }
    }
}
于 2011-07-07T16:16:00.773 に答える
10

値が最初に null を返すのを待ってから実際の値を取得できると思うので、純粋な 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();
}
于 2015-04-02T07:15:49.880 に答える