1. ホーム
  2. c#

[解決済み] コンストラクタは非同期にできますか?

2022-03-25 19:17:44

質問

あるプロジェクトで、コンストラクタにデータを入力しようとしています。

public class ViewModel
{
    public ObservableCollection<TData> Data { get; set; }

    async public ViewModel()
    {
        Data = await GetDataTask();
    }

    public Task<ObservableCollection<TData>> GetDataTask()
    {
        Task<ObservableCollection<TData>> task;

        //Create a task which represents getting the data
        return task;
    }
}

残念ながら、エラーが発生しました。

モディファイアの async はこのアイテムには有効ではありません

もちろん、標準的なメソッドでラップして、それをコンストラクタから呼び出すと。

public async void Foo()
{
    Data = await GetDataTask();
}

は正常に動作します。同様に、古いインサイドアウトの方法を使用する場合

GetData().ContinueWith(t => Data = t.Result);

それも有効ですね。ただ、どうして await をコンストラクタ内から直接呼び出すことができます。おそらく、たくさんの(明白な)エッジケースや反対の理由があるのでしょうが、私には思いつきません。また、説明を求めていろいろと検索してみましたが、見つからないようです。

解決方法は?

コンストラクタは、構築された型を返すメソッドと非常によく似た動作をします。そして async メソッドは任意の型を返すことはできず、"fire and forget "でなければなりません。 void または Task .

型のコンストラクタを使用する場合 T 実際に返された Task<T> というのは、非常に分かりにくいと思います。

もし非同期コンストラクタが async void メソッドを使用すると、コンストラクタの意味が壊れてしまいます。コンストラクタが戻った後は、完全に初期化されたオブジェクトを取得する必要があります。将来の未定義の時点で実際に適切に初期化されるようなオブジェクトではありません。運良く非同期初期化に失敗しなければの話ですが。

これらはすべて推測に過ぎません。しかし、非同期コンストラクタの可能性を持つことは、その価値よりも多くのトラブルをもたらすように思えます。

の「ファイア・アンド・フォーゲット」セマンティクスが必要な場合。 async void メソッド (これはできれば避けたいものです) を使用すると、すべてのコードを簡単に async void メソッドを作成し、それをコンストラクタから呼び出すことができます。