代码之家  ›  专栏  ›  技术社区  ›  Razor

异步实现

  •  0
  • Razor  · 技术社区  · 15 年前

    我正在尝试开发一个支持异步方法调用的类。这是我迄今为止提出的,但是,我不确定这是否是正确的做法。

    我只希望异步方法执行一次,它不需要支持多个执行,因此我不使用 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)
                    );
                }
            }
        }
    }
    
    1 回复  |  直到 12 年前
        1
  •  2
  •   bendewey    15 年前

    处理异步模型有两种主要方法,请参阅有关 Asynchronous Programming Model . 似乎您正在尝试使用IAsyncResult技术。我倾向于只在低级系统IO操作中使用它。

    对于UI或API,我倾向于使用事件模型,因为我认为它更容易处理。对于您的案例,您可以向 QueueUserWorkItem ,跟踪同步上下文,并在触发完成的事件时使用它。(如果使用WPF,可以使用DispatchHobject代替)。

    这里有一个我以前使用过的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;
            }
        }
    }