我正在尝试开发一个支持异步方法调用的类。这是我到目前为止所提出的,但是,我不确定它是否是“正确的方法”。
我只希望异步方法执行一次,它不必支持多次执行,因此我没有使用AsyncOperationManager
类。
知道异步模式的人能否给我一些反馈?我这样做是正确的吗?
任何帮助都会受到赞赏,因为我无法找到有关单一调用异步方法的任何信息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
namespace ConsoleApplication1 {
public delegate void WorkerDelegate();
class Program {
static void Main(string[] args) {
String taskId = new Guid().ToString();
AsyncTest test = new AsyncTest();
test.DoSomethingLongAsyncCompleted += new AsyncCompletedEventHandler(test_DoSomethingLongAsyncCompleted);
test.DoSomethingLongProgressChanged += new ProgressChangedEventHandler(test_DoSomethingLongProgressChanged);
test.DoSomethingLongAsync(ItsOver, taskId);
// Cancel after 2 seconds
Thread.Sleep(2000);
test.DoSomethingLongCancelAsync();
Console.ReadLine(); //Pause the console window
}
static void test_DoSomethingLongProgressChanged(object sender, ProgressChangedEventArgs e) {
Console.WriteLine("Percent complete: " + e.ProgressPercentage);
}
static void test_DoSomethingLongAsyncCompleted(object sender, AsyncCompletedEventArgs e) {
Console.WriteLine("Cancelled? " + e.Cancelled);
Console.WriteLine("Task ID: " + (String)e.UserState);
}
static void ItsOver(IAsyncResult r) {
Console.WriteLine("Task ID: " + (String)r.AsyncState);
}
}
class AsyncTest {
IAsyncResult _asyncResult = null;
Object _stateObj = null;
AsyncCallback _callBackDelegate;
public event ProgressChangedEventHandler DoSomethingLongProgressChanged;
public event AsyncCompletedEventHandler DoSomethingLongAsyncCompleted;
public IAsyncResult DoSomethingLongAsync(AsyncCallback userCallback, Object userState) {
if (_stateObj != null)
throw new InvalidOperationException("Method already started");
WorkerDelegate worker = new WorkerDelegate(DoSomethingLong);
_callBackDelegate = userCallback;
_asyncResult = worker.BeginInvoke(null, userState);
return _asyncResult;
}
public void DoSomethingLongCancelAsync() {
_stateObj = null;
}
public void DoSomethingLong() {
// Set state object if method was called synchronously
if (_stateObj == null)
_stateObj = new Object();
for (int i = 0; i < 10; i++) {
//If state object is null, break out of operation
if (_stateObj == null) break;
Thread.Sleep(1000);
Console.WriteLine("Elapsed 1sec");
if (DoSomethingLongProgressChanged != null) {
// Percentage calculation for demo only :-)
DoSomethingLongProgressChanged(this, new ProgressChangedEventArgs(i+1 * 10, _stateObj));
}
}
// Only execute if method was called async
if (_callBackDelegate != null) {
_callBackDelegate(_asyncResult);
DoSomethingLongAsyncCompleted(
this,
new AsyncCompletedEventArgs(null, (_stateObj == null), _asyncResult.AsyncState)
);
}
}
}
}
答案 0 :(得分:2)
有两种主要方法可以处理异步模型,请查看Asynchronous Programming Model上的这篇MSDN文章。您似乎正在尝试使用IAsyncResult技术。我倾向于仅将此用于低级系统IO操作。
对于UI或API,我倾向于使用事件模型,因为我认为它更容易处理。对于您的情况,您可以向QueueUserWorkItem发送事件,跟踪SynchronizationContext并在触发已完成的事件时使用它。 (如果您使用的是WPF,则可以使用DispatchObject。)
这是我之前使用过的一个ContactLoader类。
public class ContactLoader
{
public List<Contact> Contacts { get; private set; }
private readonly IRepository<Contact> contactsRepository;
public ContactLoader(IRepository<Contact> contactsRepository)
{
this.contactsRepository = contactsRepository;
}
public event AsyncCompletedEventHandler Completed;
public void OnCompleted(AsyncCompletedEventArgs args)
{
if (Completed != null)
Completed(this, args);
}
public bool Cancel { get; set; }
private SynchronizationContext _loadContext;
public void LoadAsync(AsyncCompletedEventHandler completed)
{
Completed += completed;
LoadAsync();
}
public void LoadAsync()
{
if (_loadContext != null)
throw new InvalidOperationException("This component can only handle 1 async request at a time");
_loadContext = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(new WaitCallback(_Load));
}
public void Load()
{
_Load(null);
}
private void _Load(object state)
{
Exception asyncException = null;
try
{
Contacts = contactsRepository.GetAll();
if (Cancel)
{
_Cancel();
return;
}
}
catch (Exception ex)
{
asyncException = ex;
}
if (_loadContext != null)
{
AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(asyncException, false, null);
_loadContext.Post(args =>
{
OnCompleted(args as AsyncCompletedEventArgs);
}, e);
_loadContext = null;
}
else
{
if (asyncException != null) throw asyncException;
}
}
private void _Cancel()
{
if (_loadContext != null)
{
AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(null, true, null);
_loadContext.Post(args =>
{
OnCompleted(args as AsyncCompletedEventArgs);
}, e);
_loadContext = null;
}
}
}