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

C# 任务的多个退出点(立即和延迟),c#,task-parallel-library,task,C#,Task Parallel Library,Task,我试图将两个独立函数的功能连接到一个任务中。我可能有点迂腐,但我也很好奇这是否可能,所以希望一些C#wizard能找到答案 这是当前设置 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 a

我试图将两个独立函数的功能连接到一个任务中。我可能有点迂腐,但我也很好奇这是否可能,所以希望一些C#wizard能找到答案

这是当前设置

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();
}
我想将这两个函数移到一个任务中,该任务只返回
数据
,当然,一个任务只能返回一次

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

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();
}
异步任务GetData() { //立即从数据库中获取一些缓存数据 返回FetchDataLocal(); //当本地数据可用时,将其替换为来自web的数据 返回wait wait FetchDataRemote(); }
是否有某种任务解决方案允许您执行类似的操作?因此,任务将返回两次数据(即时数据和延迟数据)。该解决方案甚至可能不是一项任务,但我不确定它将是什么。

您可以创建一个自定义类,该类保存对象并在更新事件时刷新事件

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));
    }
}
公共类延迟数据:INotifyPropertyChanged
{
公共延迟数据(T缓存数据、任务数据工厂)
{
_数据=缓存数据;
DatabaseLookupTask=dataFactory.ContinueWith(任务=>Data=task.Result,CancellationToken.None,TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.FromCurrentSynchronizationContext());
}
私人T_数据;
公共T数据
{
获取{return_data;}
专用设备
{
如果(等于(值,_数据))返回;
_数据=价值;
OnPropertyChanged();
}
}
公共任务数据库lookuptask{get;}
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChanged?.Invoke(这是新的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);
    }
DeferredData GetData()
{
//立即从数据库中获取一些缓存数据
var localData=FetchDataLocal();
//当本地数据可用时,将其替换为来自web的数据
var remoteTask=FetchDataRemote();
返回新的延迟数据(localData、remoteTask);
}

假设您在MVVM应用程序中工作,我建议使用,它可以为您处理
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);
}
公共任务数据;
ViewModelConstructor()
{
//立即从数据库中获取一些缓存数据
var immediateData=FetchDataLocal();
//当本地数据可用时,将其替换为来自web的数据
Data=NotifyTask.Create(FetchDataRemote(),immediateData);
}

如果您确实使用了
NotifyTask
,则需要将数据绑定到
数据。结果

感谢您提供详细答案,立即测试您的代码。由于平台的限制,我正在使用.NET 4.5,
TaskContinuationOptions.RunContinuationsAsynchronously
是.NET 4.6的一项功能。是否有解决方法?干杯。没有itI应该没问题。我正在使用MVVM应用程序。很好,我来试试。嗨,Stephen,我已经实现了NotifyTask,我正在尝试返回Data.Result(其中数据是NotifyTask对象)。然后将其分配给我的视图模型中的一个属性(该属性实现了RaisePropertyChanged的MvvmCross版本)。在NotifyTask中调用NotifyProperties时,propertyChanged事件为null。如何在视图模型中连接MvvmCross属性?有点模糊的问题抱歉。
NotifyTask
设计为直接绑定到的数据。如果要“传播”结果,需要连接到
((INotifyPropertyChanged)NotifyTask).PropertyChanged
并从此处设置您自己的属性。我感觉您可以这样说:)太好了,这样将在ViewModel中调用属性的setter,这将引发其自己的属性更改事件,并向下传播到UI。好吧,我会试着想出一个好办法把它整齐地包起来。非常感谢。p、 我将使用TestUtils.PropertyNotified作为起点调用代码是什么样子的?一个名为ReportService的服务类中的单个任务函数,它只关心获取Report类型的对象。我希望它立即返回本地报告,然后当web fetch返回时,它将从web数据返回新报告。Task函数是服务类中的一系列任务的一部分,这些任务是从UI项目Xamarin.IOS中的ICommand启动的,该命令在输入视图时触发。我正在数据绑定到视图模型中的报表属性。这也是ICommand所在的位置。所有这些都构建在MVVM体系结构上。