gpt4 book ai didi

.net - 如何使用 TaskFactory.FromAsync 和自定义 Async 过程创建任务

转载 作者:行者123 更新时间:2023-11-30 23:51:39 24 4
gpt4 key购买 nike

我正在尝试测试一些依赖 Task 进行后台计算的类(从网络位置检索数据)。该类获取一个未启动的任务实例,添加一个 ContinueWith 方法,然后在该任务上调用 Start。像这样的东西:

private void Search()
{
Task<SearchResults> searchTask = m_searchProvider.GetSearchTask(m_searchCriteria);
searchTask.ContinueWith(OnSearchTaskCompleted);
searchTask.Start();
}

该类通过接口(interface)获取 Task 的实例,因此我能够注入(inject)我的测试控制的 Task 实例。但是,我似乎无法创建一个我有足够控制权的东西。

我不想在测试中引入线程,但仍然想让Task异步运行,所以我尝试做的是编写一个实现BeginInvoke/EndInvoke模式的类,没有线程,并使用TaskFactory.FromAsync方法创建任务。

这个想法是测试可以调用启动任务的类上的方法,然后当它返回时,测试可以将结果数据提供给 Async 对象,该对象完成操作,同时保持在同一个线程上。

但是,当我尝试在该任务上调用 Start 时,我收到一条错误消息,指出“可能不会在具有空操作的任务上调用 Start”。不幸的是,谷歌对该消息没有太大帮助,所以我不确定我是否错误地实现了我的 Async 对象,或者错误地使用了 TaskFactory.FromAsync。这是我的 NonThreadedAsync 类的代码和一个因异常而崩溃的测试:
public class NonThreadedAsync<TResult>
{
private NonThreadedAsyncResult<TResult> m_asyncResult;

public IAsyncResult BeginInvoke(
AsyncCallback callback,
object state)
{
m_asyncResult = new NonThreadedAsyncResult<TResult>(callback, state);
return m_asyncResult;
}

public TResult EndInvoke(IAsyncResult asyncResult)
{
return m_asyncResult.GetResults();
}

public void Complete(TResult data)
{
m_asyncResult.CompleteAsync(data);
}
}

public class NonThreadedAsyncResult<TResult> : IAsyncResult
{
private readonly AsyncCallback m_asyncCallback;
private readonly object m_state;
private readonly ManualResetEvent m_waitHandle;
private bool m_isCompleted;
private TResult m_resultData;

public NonThreadedAsyncResult(AsyncCallback asyncCallback, object state)
{
m_asyncCallback = asyncCallback;
m_state = state;
m_waitHandle = new ManualResetEvent(false);
m_isCompleted = false;
}

public void CompleteAsync(TResult data)
{
m_resultData = data;
m_isCompleted = true;
m_waitHandle.Set();
if (m_asyncCallback != null)
{
m_asyncCallback(this);
}
}

public TResult GetResults()
{
if (!m_isCompleted)
{
m_waitHandle.WaitOne();
}
return m_resultData;
}

#region Implementation of IAsyncResult

public bool IsCompleted
{
get { return m_isCompleted; }
}

public WaitHandle AsyncWaitHandle
{
get { return m_waitHandle; }
}

public object AsyncState
{
get { return m_state; }
}

public bool CompletedSynchronously
{
get { return false; }
}

#endregion
}

[TestClass]
public class NonThreadedAsyncTests
{
[TestMethod]
public void TaskFactoryFromAsync_CanStartReturnedTask()
{
NonThreadedAsync<int> async = new NonThreadedAsync<int>();

Task<int> task = Task<int>.Factory.FromAsync(async.BeginInvoke, async.EndInvoke, null);

task.Start();
}
}

作为进一步的信息,如果我调试该测试,就在它调用 Start() 之前,任务实例将显示在 Locals 窗口中,如下所示:
Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
但是如果我展开它,可见属性中没有 Method 属性。

谁能看到我做错了什么?

[编辑:我还编写了一个测试,确认 NonThreadedAsync 类与经典的 Begin/End 模式(或者至少,我对 Begin/End 模式的理解 :))正常工作,并且通过了:
[TestMethod]
public void NonThreadedAsync_ClassicAccessPattern()
{
int result = 0;
bool asyncCompleted = false;

NonThreadedAsync<int> async = new NonThreadedAsync<int>();

async.BeginInvoke(asyncResult =>
{
result = async.EndInvoke(asyncResult);
asyncCompleted = true;
},
null);

Assert.IsFalse(asyncCompleted);
Assert.AreEqual(0, result);

async.Complete(54);

Assert.IsTrue(asyncCompleted);
Assert.AreEqual(54, result);
}

最佳答案

哦,我明白了。我们的 API 是错误的,因为它试图返回未启动的任务。从被测类中删除 Start() 解决了这个问题。然而,在研究这一点时,我还发现我为获得测试控制的异步任务做的太多了。根据 Stephen Toub 的帖子 here ,我们可以简单地使用TaskCompletionSource:

[TestMethod]
public void TaskCompletionSource_WorksALotBetterThanMyOverEngineeredCustomStuff()
{
int result = 0;

TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();

Task<int> myTask = tcs.Task;

// Pretend this is the class under test and that we've
// passed in myTask
myTask.ContinueWith(t => { result = t.Result; },
TaskContinuationOptions.ExecuteSynchronously);

Assert.AreEqual(0, result);

tcs.SetResult(54);

Assert.AreEqual(54, result);
}

关于.net - 如何使用 TaskFactory.FromAsync 和自定义 Async 过程创建任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5575620/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com