8

考虑以下“即发即弃”用例:

调用者从我的方法中请求一些数据。我的方法检查缓存以查看数据是否已经存在。如果不是,它会从源中获取并缓存它。调用者在获取结果之前不需要等待缓存发生,并且如果缓存碰巧失败,该方法不应阻止调用者获取结果。我今天所拥有的,看起来像这样:

public Foo GetFoo(string fooKey)
{
    // look for Foo with fooKey in cache
    // if Foo is not found, get Foo with fooKey from source
    // and assign it to local variable myFoo
    Task cacheTask 
           = Task.Run
                (
                    () => CacheFoo(myFoo)// fire-and-forget the caching of myFoo
                ); 
    return myFoo;
}

如果 CacheFoo 抛出一个异常,它不会被观察到,最终(在 .Net 4.5 中)它会被框架吞噬。我宁愿自己最后一次清理异常,但我不想阻塞当前线程。最好的方法是什么?

这是我尝试过的

try
{
    ...
   cacheTask.ContinueWith
            (
                (e) => { 
                         if (cacheTask.IsFaulted) 
                            { 
                             /* log cacheTask.Exception */; 
                             } 
                        }
                , TaskContinuationOptions.OnlyOnFaulted
            ); 
}

有没有更好的办法?我是否需要 IsFaulted 上的“if”语句,还是因为我已经指定了“OnlyOnFaulted”而显得多余?

任何意见/建议将不胜感激。

4

1 回答 1

11

四件事:

  • 不,您不需要Task.IsFaulted 属性;回调只有在出错时才会触发
  • 你不需要捕捉cacheTask;您的回调中的thee是相同的任务,因此您不妨改用它。(然后同一个委托可以用于所有任务。)
  • 如果您总是以相同的方式登录,您可能希望在任务上编写一个扩展方法,以便轻松执行此操作
  • 作为添加处理程序的替代方法,您可以考虑订阅TaskScheduler.UnobservedTaskException并在那里执行日志记录
于 2013-04-11T16:05:50.070 回答