Как заставить мою функцию правильно использовать обратный вызов после завершения асинхронных функций?

У меня есть функция, которая загружает несколько ресурсов через асинхронный режим, и я хочу вызвать действие onComplete, когда все ресурсы загружены, но в настоящее время, учитывая природу асинхронности, я не уверен, как заставить мою функцию делать это, поскольку я относительно новичок. программированию в асинхронном режиме.

public void Load(Action onComplete)
{
    foreach (var kvp in _db)
    {
        var key = kvp.Key;
        var assetRef = kvp.Value;
        assetRef.LoadAssetAsync<TAsset>().Completed += handle =>
        {
            if (handle.Status == AsyncOperationStatus.Succeeded)
                _loadedAssets.Add(key, handle.Result);

            //check if all assets have been loaded and then call onComplete
        };
    }
}

🤔 А знаете ли вы, что...
C# обеспечивает возможность создания многопоточных приложений с помощью пространства имен System.Threading.


62
1

Ответ:

Решено

Вам следует использовать Microsoft Reactive Framework (он же Rx) — NuGet System.Reactive и добавить using System.Reactive.Linq; — тогда вы сможете сделать это:

public void Load2(Action onComplete)
{
    (
        from kvp in _db.ToObservable()
        let key = kvp.Key
        let assetRef = kvp.Value
        let assetLoader = assetRef.LoadAssetAsync<TAsset>()
        from handle in
            Observable
                .FromEvent<Action<AssetHandle>, AssetHandle>(
                    h => assetLoader.Completed += h,
                    h => assetLoader.Completed -= h)
                .Take(1)
        where handle.Status == AsyncOperationStatus.Succeeded
        select new { key, handle.Result }
    )
        .Subscribe(
            x => _loadedAssets.Add(x.key, x.Result),
            () => onComplete());
}

Теперь это должно сработать. Мне пришлось перепроектировать некоторые типы, но, думаю, я с этим справился. Состояние гонки все еще существует в вашем коде.