任务的多个退出点(立即和延迟)

时间:2016-09-21 13:45:09

标签: c# task-parallel-library task

我试图将两个独立函数的功能连接到一个Task中。我可能很迂腐,但我也很想知道这是否可能,所以希望有一些C#向导有答案。

这是当前的设置。

async Task GetData()
{
    // Get some cached data immediately from the database
    Data = FetchDataLocal(); 

    // Replace the local data with the data from the web when it is available 
    Data = await FetchDataRemote();
}

我想将这两个函数移动到只返回Data的单个任务中,但当然任务只能返回一次。

所以基本上我需要这种(下面)的功能,但形式正确。我很乐观,那里有一个优雅的解决方案。

async Task<DataType> GetData()
{
    // Get some cached data immediately from the database
    return FetchDataLocal(); 

    // Replace the local data with the data from the web when it is available 
    return await FetchDataRemote();
}

是否有某种任务解决方案允许您执行此类操作?因此,任务将返回两次数据(即时数据,然后是延迟数据)。解决方案可能不是一个任务,但我不确定它会是什么。

2 个答案:

答案 0 :(得分:2)

假设您正在使用MVVM应用程序,我建议使用my NotifyTask<T> type,它会为您处理INotifyPropertyChanged内容:

public NotifyTask<TData> Data;

ViewModelConstructor()
{
  // Get some cached data immediately from the database
  var immediateData = FetchDataLocal(); 

  // Replace the local data with the data from the web when it is available
  Data = NotifyTask.Create(FetchDataRemote(), immediateData);
}

如果您使用NotifyTask<T>,那么您需要数据绑定到Data.Result

答案 1 :(得分:0)

您可以创建一个包含两个对象的自定义类,并在事件更新时发出事件。

public class DeferredData<T> : INotifyPropertyChanged
{
    public DeferredData(T cachedData, Task<T> dataFactory)
    {
        _data = cachedData;
        DatabaseLookupTask = dataFactory.ContinueWith(task => Data = task.Result, CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously,
            TaskScheduler.FromCurrentSynchronizationContext());
    }

    private T _data;

    public T Data
    {
        get { return _data; }
        private set
        {
            if (Equals(value, _data)) return;
            _data = value;
            OnPropertyChanged();
        }
    }

    public Task DatabaseLookupTask { get; }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

一样使用
    DeferredData<DataType> GetData()
    {
        // Get some cached data immediately from the database
        var localData = FetchDataLocal();

        // Replace the local data with the data from the web when it is available 
        var remoteTask = FetchDataRemote();

        return new DeferredData<DataType>(localData, remoteTask);
    }