【WP8】同步執行非同步代碼

來源:互聯網
上載者:User

標籤:style   blog   http   color   os   使用   io   ar   for   

微軟的StorageFile只支援非同步方式進行檔案操作,我之前也封裝過一個StorageHelper,但是當所有的方法都是非同步時候也帶來一些問題

  1、比如我們不能在建構函式調用非同步代碼(等待),

  2、比如我們在離開App的時候我們需要對資料進行快速的儲存(在事件中),這個時候就不適合用非同步了,非同步可能會導致儲存失敗,因為App已經不在前台了

最近就遇到了一個這樣的需求

  我封裝了一個SqliteHelper類,提供了一些資料庫操作的一些常用方法,在資料庫使用之前,需要保證資料庫路徑的檔案夾是存在的,如果不能存在,則會拋出異常,所以在SqliteHelper的建構函式判斷該檔案夾是否存在,如果不存在,則建立該檔案夾,但是StorageHelper不支援同步方法(這裡不使用IsolatedStorage),我們需要保證在StorageHelper在構造完成時,保證檔案夾存在

    public SqliteHelper(string dbPath)    {        this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);        var directory = Path.GetDirectoryName(dbPath);        if (directory != null)        {            //TODO:建構函式不支援await關鍵字            //await StorageHelper.Instance.CreateDirectoryAsync(directory);        }    }

  滿足上面需求可以有兩個方法:

  1、通過一個靜態非同步方法呼叫來構造SqliteHelper的執行個體,把非同步作業放到非同步方法呼叫裡面,但是這種方法會導致不能使用依賴注入IoC

    private SqliteHelper(string dbPath)    {        this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);    }    public static async Task<SqliteHelper> GetSqliteHelper(string dbPath)    {        var sqliteHelper = new SqliteHelper(dbPath);        var directory = Path.GetDirectoryName(dbPath);        if (directory != null)        {            await StorageHelper.Instance.CreateDirectoryAsync(directory);        }        return sqliteHelper;    }

 

  2、讓非同步方法呼叫同步執行

    我們首先定義一個非同步執行Helper,提供非同步方法呼叫的同步(摘自後面的參考文章)

using System;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks;namespace TestDemo{    public static class AsyncInline    {        public static void Run(Func<Task> item)        {            var oldContext = SynchronizationContext.Current;            var synch = new ExclusiveSynchronizationContext();            SynchronizationContext.SetSynchronizationContext(synch);            synch.Post(async _ =>            {                try                {                    await item();                }                catch (Exception e)                {                    synch.InnerException = e;                    throw;                }                finally                {                    synch.EndMessageLoop();                }            }, null);            synch.BeginMessageLoop();            SynchronizationContext.SetSynchronizationContext(oldContext);        }        public static T Run<T>(Func<Task<T>> item)        {            var oldContext = SynchronizationContext.Current;            var synch = new ExclusiveSynchronizationContext();            SynchronizationContext.SetSynchronizationContext(synch);            T ret = default(T);            synch.Post(async _ =>            {                try                {                    ret = await                    item();                }                catch (Exception e)                {                    synch.InnerException = e;                    throw;                }                finally                {                    synch.EndMessageLoop();                }            }, null);            synch.BeginMessageLoop();            SynchronizationContext.SetSynchronizationContext(oldContext);            return ret;        }        private class ExclusiveSynchronizationContext : SynchronizationContext        {            private bool done;            public Exception InnerException { get; set; }            readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);            readonly Queue<Tuple<SendOrPostCallback, object>> items =             new Queue<Tuple<SendOrPostCallback, object>>();            public override void Send(SendOrPostCallback d, object state)            {                throw new NotSupportedException("We cannot send to our same thread");            }            public override void Post(SendOrPostCallback d, object state)            {                lock (items)                {                    items.Enqueue(Tuple.Create(d, state));                }                workItemsWaiting.Set();            }            public void EndMessageLoop()            {                Post(_ => done = true, null);            }            public void BeginMessageLoop()            {                while (!done)                {                    Tuple<SendOrPostCallback, object> task = null;                    lock (items)                    {                        if (items.Count > 0)                        {                            task = items.Dequeue();                        }                    }                    if (task != null)                    {                        task.Item1(task.Item2);                        if (InnerException != null) // the method threw an exeption                        {                            throw new AggregateException("AsyncInline.Run method threw an exception.",                             InnerException);                        }                    }                    else                    {                        workItemsWaiting.WaitOne();                    }                }            }            public override SynchronizationContext CreateCopy()            {                return this;            }        }    }}

    接下來我們就可以像同步方法一樣使用非同步方法呼叫了

    public class TestClass    {        public int Id { get; set; }        public TestClass()        {            //這裡調用一個非同步方法呼叫,等待非同步方法呼叫執行返回            Id = AsyncInline.Run(GetIdAsync);            //不支援await            //await GetIdAsync();        }        /// <summary>        /// 非同步方法呼叫        /// </summary>        public async Task<int> GetIdAsync()        {            //TODO:這裡執行類比自訂動作            await Task.Delay(1000);            return 10;        }    }

 

 

參考文章:

  http://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async

  http://stackoverflow.com/questions/8145479/can-constructors-be-async

 

個人能力有限,如果有更好的實現,可以給我留言

轉載請註明出處:http://www.cnblogs.com/bomo/p/3942750.html

 

【WP8】同步執行非同步代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.