7

我正在寻找一种在后台执行任务的简单方法,然后在完成时更新某些内容(在主线程上)。它在一个低级的“模型”类中,所以我不能调用 InvokeOnMainThread,因为我周围没有 NSObject。我有这个方法:

public void GetItemsAsync(Action<Item[]> handleResult)
{
  Item[] items=null;
  Task task=Task.Factory.StartNew(() =>
  {
    items=this.CreateItems(); // May take a second or two
  });
  task.ContinueWith(delegate
  {
    handleResult(items);
  }, TaskScheduler.FromCurrentSynchronizationContext());
}

这似乎工作正常,但是

1)这是最好(最简单)的方式吗?

2)我担心局部变量:

Item{} items=null

当方法在后台线程完成之前返回时,是什么阻止了这种消失?

谢谢。

4

4 回答 4

2

像这样的东西:

    public void GetItemsAsync(Action<Item[]> handleResult)
    {
        int Id = 11;
        Task<Item[]> task = Task.Factory.StartNew(() => CreateItems(Id)); // May take a second or two
        task.ContinueWith(t => handleResult(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
    }
于 2012-11-27T10:05:41.993 回答
2

我认为你的方法稍微违反了单一责任原则,因为它做得太多了。

首先,我建议更改CreateItems为 returnTask而不是将其包装在GetItemsAsync

public Task<Item[]> CreateItems(CancellationToken token)
{
   return Task.Factory.StartNew(() => 
     // obtaining the data...
     {});
}

CancellationToken是可选的,但如果您能够取消此长时间运行的操作,则可以为您提供帮助。

使用此方法,您可以完全删除GetItemsAsync,因为它可以很简单地由您的客户端处理结果而无需传递此委托:

// Somewhere in the client of your class
var task = yourClass.CreateItems(token);
task.ContinueWith(t => 
 // Code of the delegate that previously
 // passed to GetItemsAsync method
 {}, TaskScheduler.FromCurrentSynchronizationContext());

Using this approach you'll get more clear code with only one responsibility. Task class itself is a perfect tool for representing asynchronous operation as a first class object. Using proposed technique you can easily mock you current implementation with a fake behavior for unit testing without changing your clients code.

于 2012-11-27T10:43:42.203 回答
1

你的代码看起来不错。

async / await如果可以使用 C# 5,这是一个完美的示例,但如果不能,则必须像使用 continuation 一样编写它。

items变量在您的 lambda 表达式中被捕获,所以这也很好。

当您编写使用外部变量的 lambda 时,C# 编译器会创建一个包含该变量的类。这称为闭包,意味着您可以访问 lambda 中的变量。

于 2012-11-27T10:04:25.803 回答
1

这是一个更好的灵魂:

    public void GetItemsAsync(Action<Item[]> handleResult)
    {
        var task = Task.Factory.StartNew<Item[]>(() =>
        {
            return this.CreateItems(); // May take a second or two
        });

        task.ContinueWith(delegate
        {
            handleResult(task.Result);
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
于 2012-11-27T10:04:25.880 回答