我有一些代码如下:
的Class1
Task<List<ConfSession>> getSessionsTask = Task.Factory.StartNew(() =>
{
var confSessions =
TaskHelper<ConfSession>.InvokeTaskMagic(request);
//PROBLEM - THIS CODE RACES TO THE NEXT LINE
//BEFORE confSessions IS POPULATED FROM THE LINE ABOVE - IE
//confSessions IS ALWAYS AN EMPTY LIST
//WHEN IT'S RETURNED
return confSessions;
}
);
Class2(TaskHelper)
//methods
public static List<T> InvokeTaskMagic(HttpWebRequest request)
{
var resultList = new List<T>();
Task<WebResponse> task1 = Task<WebResponse>.Factory.FromAsync(
(callback, o) => ((HttpWebRequest)o).BeginGetResponse(callback, o)
, result => ((HttpWebRequest)result.AsyncState).EndGetResponse(result)
, request);
task1.ContinueWith((antecedent) =>
{
if (antecedent.IsFaulted)
{
return;
}
WebResponse webResponse;
try
{
webResponse = task1.Result;
}
catch (AggregateException ex1)
{
throw ex1.InnerException;
}
string responseString;
using (var response = (HttpWebResponse)webResponse)
{
using (Stream streamResponse = response.GetResponseStream())
{
StreamReader reader = new StreamReader(streamResponse);
responseString = reader.ReadToEnd();
reader.Close();
}
}
if (responseString != null)
{
resultList =
JsonConvert.DeserializeObject<List<T>>(responseString);
}
});
return resultList;
}
TaskHelper是我创建的一个类,用于标准化我在几种方法中使用的一堆冗余任务代码。它仅用于获取HttpWebRequest,在Task中执行它,在ContinueWith块中获取响应,将响应解析为List<T>
,然后返回List<T>
。
我在一个任务中包装了Class1对TaskHelper的调用,因为我需要在继续class1之前从InvokeTaskMagic方法获取结果(即class1中的下一步是使用List<T>
。正如它在在代码中的注释,我的问题是class1中的Task每次都返回一个空列表,因为它不等待TaskHelper类中的InvokeTaskMagic方法的响应。
这是预期的吗?有没有办法使getSessionsTask等待返回,直到TaskHelper.InvokeTaskMagic返回?
更新: 工作代码如下 - 感谢Servy的帮助。
public static class TaskHelper<T> where T : class
{
//methods
public static Task<List<T>> InvokeTaskMagic(HttpWebRequest request)
{
var resultList = new List<T>();
Task<WebResponse> task1 = Task<WebResponse>.Factory.FromAsync(
(callback, o) => ((HttpWebRequest)o).BeginGetResponse(callback, o)
, result => ((HttpWebRequest)result.AsyncState).EndGetResponse(result)
, request);
return task1.ContinueWith<List<T>>((antecedent) =>
{
if (antecedent.IsFaulted)
{
return new List<T>();
}
WebResponse webResponse;
try
{
webResponse = task1.Result;
}
catch (AggregateException ex1)
{
throw ex1.InnerException;
}
string responseString;
using (var response = (HttpWebResponse)webResponse)
{
using (Stream streamResponse = response.GetResponseStream())
{
StreamReader reader = new StreamReader(streamResponse);
responseString = reader.ReadToEnd();
reader.Close();
}
}
if (responseString != null)
{
return JsonConvert.DeserializeObject<List<T>>(responseString);
}
else
{
return new List<T>();
}
});
}
}
调用InvokeTaskMagic方法如下:
var getCommentsAboutTask = Task.Factory.StartNew(() =>
{
var comments = TaskHelper<Comment>.InvokeTaskMagic(request);
return comments;
});
getCommentsAboutTask.ContinueWith((antecedent) =>
{
if (antecedent.IsFaulted)
{ return; }
var commentList = antecedent.Result.Result;
UIThread.Invoke(() =>
{
foreach (Comment c in commentList)
{
AllComments.Add(c);
GetCommentRelatedInfo(c);
}
});
});
答案 0 :(得分:8)
这是预期的吗?有没有办法让我的class1.task1 continueblock等待我的class2.task2 continueblock?
当然,只需在第二个任务的延续而不是第一个任务上调用ContinueWith
。
如果您需要等到两者都完成,您可以使用Task.Factory.ContinueWhenAll
。
答案 1 :(得分:1)
我前段时间做过与你的代码类似的事情,很难让它在错误处理等方面正常工作。
首先,我创建了一个泛型方法来处理具有不同返回类型的延续
private AsyncCallback EndAsync<T1, T2>(TaskCompletionSource<T2> tcs,
Func<IAsyncResult, T1> endMethod,
Func<T1, T2> continueWith) {
return ar => {
T1 result1;
try {
result1 = endMethod(ar);
}
catch (Exception err) {
tcs.SetException(err);
return;
}
try {
T2 result2 = continueWith(result1);
tcs.SetResult(result2);
}
catch (Exception err) {
tcs.SetException(err);
return;
}
};
}
然后我创建这样的异步任务:
public Task<List<T>> GetDataAsync(IProxy proxy) {
var tcs = new TaskCompletionSource<List<T>>();
var asyncCallback = EndAsync(tcs,
proxy.EndGetData,
result => result != null ?
ProcessResult(result) :
new List<T>());
proxy.BeginGetData(asyncCallback);
return tcs.Task;
}