微软的StorageFile只支持异步的方式进行文件操作,我之前也封装过一个StorageHelper,但是当所有的方法都是异步的时候也带来一些问题

  1、比如我们不能在构造函数调用异步代码(等待),

  2、比如我们在离开App的时候我们需要对数据进行快速的保存(在事件中),这个时候就不适合用异步了,异步可能会导致保存失败,因为App已经不在前台了

最近就遇到了一个这样的需求

  我封装了一个SqliteHelper类,提供了一些数据库操作的一些常用方法,在数据库使用之前,需要保证数据库路径的文件夹是存在的,如果不能存在,则会抛出异常,所以在SqliteHelper的构造函数判断该文件夹是否存在,如果不存在,则创建该文件夹,但是StorageHelper不支持同步方法(这里不使用IsolatedStorage),我们需要保证在StorageHelper在构造完成时,保证文件夹存在

  1. public SqliteHelper(string dbPath)
  2. {
  3. this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);
  4. var directory = Path.GetDirectoryName(dbPath);
  5. if (directory != null)
  6. {
  7. //TODO:构造函数不支持await关键字
  8. //await StorageHelper.Instance.CreateDirectoryAsync(directory);
  9. }
  10. }

  满足上面需求可以有两个方法:

  1、通过一个静态异步方法来构造SqliteHelper的实例,把异步操作放到异步方法里面,但是这种方法会导致不能使用依赖注入IoC

  1. private SqliteHelper(string dbPath)
  2. {
  3. this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);
  4. }
  5.  
  6. public static async Task<SqliteHelper> GetSqliteHelper(string dbPath)
  7. {
  8. var sqliteHelper = new SqliteHelper(dbPath);
  9. var directory = Path.GetDirectoryName(dbPath);
  10. if (directory != null)
  11. {
  12. await StorageHelper.Instance.CreateDirectoryAsync(directory);
  13. }
  14. return sqliteHelper;
  15. }

  2、让异步方法同步执行

    我们首先定义一个异步执行Helper,提供异步方法的同步(摘自后面的参考文章)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5.  
  6. namespace TestDemo
  7. {
  8. public static class AsyncInline
  9. {
  10. public static void Run(Func<Task> item)
  11. {
  12. var oldContext = SynchronizationContext.Current;
  13. var synch = new ExclusiveSynchronizationContext();
  14. SynchronizationContext.SetSynchronizationContext(synch);
  15. synch.Post(async _ =>
  16. {
  17. try
  18. {
  19. await item();
  20. }
  21. catch (Exception e)
  22. {
  23. synch.InnerException = e;
  24. throw;
  25. }
  26. finally
  27. {
  28. synch.EndMessageLoop();
  29. }
  30. }, null);
  31. synch.BeginMessageLoop();
  32. SynchronizationContext.SetSynchronizationContext(oldContext);
  33. }
  34. public static T Run<T>(Func<Task<T>> item)
  35. {
  36. var oldContext = SynchronizationContext.Current;
  37. var synch = new ExclusiveSynchronizationContext();
  38. SynchronizationContext.SetSynchronizationContext(synch);
  39. T ret = default(T);
  40. synch.Post(async _ =>
  41. {
  42. try
  43. {
  44. ret = await
  45. item();
  46. }
  47. catch (Exception e)
  48. {
  49. synch.InnerException = e;
  50. throw;
  51. }
  52. finally
  53. {
  54. synch.EndMessageLoop();
  55. }
  56. }, null);
  57. synch.BeginMessageLoop();
  58. SynchronizationContext.SetSynchronizationContext(oldContext);
  59. return ret;
  60. }
  61.  
  62. private class ExclusiveSynchronizationContext : SynchronizationContext
  63. {
  64. private bool done;
  65. public Exception InnerException { get; set; }
  66. readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
  67. readonly Queue<Tuple<SendOrPostCallback, object>> items =
  68. new Queue<Tuple<SendOrPostCallback, object>>();
  69.  
  70. public override void Send(SendOrPostCallback d, object state)
  71. {
  72. throw new NotSupportedException("We cannot send to our same thread");
  73. }
  74. public override void Post(SendOrPostCallback d, object state)
  75. {
  76. lock (items)
  77. {
  78. items.Enqueue(Tuple.Create(d, state));
  79. }
  80. workItemsWaiting.Set();
  81. }
  82. public void EndMessageLoop()
  83. {
  84. Post(_ => done = true, null);
  85. }
  86. public void BeginMessageLoop()
  87. {
  88. while (!done)
  89. {
  90. Tuple<SendOrPostCallback, object> task = null;
  91. lock (items)
  92. {
  93. if (items.Count > )
  94. {
  95. task = items.Dequeue();
  96. }
  97. }
  98. if (task != null)
  99. {
  100. task.Item1(task.Item2);
  101. if (InnerException != null) // the method threw an exeption
  102. {
  103. throw new AggregateException("AsyncInline.Run method threw an exception.",
  104. InnerException);
  105. }
  106. }
  107. else
  108. {
  109. workItemsWaiting.WaitOne();
  110. }
  111. }
  112. }
  113. public override SynchronizationContext CreateCopy()
  114. {
  115. return this;
  116. }
  117. }
  118. }
  119. }

    接下来我们就可以像同步方法一样使用异步方法了

  1. public class TestClass
  2. {
  3. public int Id { get; set; }
  4.  
  5. public TestClass()
  6. {
  7. //这里调用一个异步方法,等待异步方法执行返回
  8. Id = AsyncInline.Run(GetIdAsync);
  9.  
  10. //不支持await
  11. //await GetIdAsync();
  12. }
  13.  
  14. /// <summary>
  15. /// 异步方法
  16. /// </summary>
  17. public async Task<int> GetIdAsync()
  18. {
  19. //TODO:这里执行模拟自定义操作
  20. await Task.Delay();
  21.  
  22. return ;
  23. }
  24. }

参考文章:

  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/3945761.html

【WP8】同步执行异步代码的更多相关文章

  1. .NET Core学习笔记(4)——谨慎混合同步和异步代码

    原则上我们应该避免编写混合同步和异步的代码,这其中最大的问题就是很容易出现死锁.让我们来看下面的例子: private void ButtonDelayBlock_Click(object sende ...

  2. Combine 框架,从0到1 —— 4.在 Combine 中执行异步代码

    本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中执行异步代码. 内容概览 前言 用 Future 取代回调闭包 用输出类型( ...

  3. redux本来是同步的为什么它能执行异步代码(chunk)实现原理是什么 中间件的实现原理是什么

    我们用redux执行同步的时候,都是先发起一个dispatch(actionCreator()) 1.先在actionCreator()中生成一个action对象. 2.由dispatch方法将act ...

  4. 使用Async同步执行异步函数

    为了适应异步编程,减少回调的嵌套,我在项目中引入了Async,当批量处理且需要同步执行一些逻辑相同的异步函数时,觉得还是Async最为靠谱. 我有一个类似下面代码的场景,依据数组中的每一个元素执行一个 ...

  5. iOS gcd 串行,并行,同步,异步代码研究

    参考文章: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #527eff } span.s1 { } http: ...

  6. node.js的作用、回调、同步异步代码、事件循环

    http://www.nodeclass.com/articles/39274 一.node.js的作用 I/O的意义,(I/O是输入/输出的简写,如:键盘敲入文本,输入,屏幕上看到文本显示输出.鼠标 ...

  7. ajax同步、异步执行简单理解与证明

    此理解范例代码来自前几篇随笔! 首先我们来先了解下AJAX: Ajax:全称“Asynchronous Javascript and XML”(异步Javascript和XML),他是由Javascr ...

  8. C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)

    C# code namespace UDPServer { class Program { static void Main(string[] args) { int recv; byte[] dat ...

  9. IOS多线程知识总结/队列概念/GCD/主队列/并行队列/全局队列/主队列/串行队列/同步任务/异步任务区别(附代码)

    进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程 队列 dispa ...

随机推荐

  1. php多路复用(多线程)socket相关应用

    最近研究php多线程的问题,发现中文资源少的可怜,仅有的几篇文章被转了又转,但文中内容价值有限.搜索过程中发现国外很多网站引用的一篇文章写的不错,所以翻译过来. 版权声明:可以任意转载,转载时请务必以 ...

  2. Memory Models And Namespaces

    分开编译 不要把变量和函数的定义放到头文件中. 可以分开编译源文件,然后将它们连接起来生成最终的可执行文件. 如果你只修改了一个文件,你可以只重新编译这个文件,之前编译过的其他文件就不需要再次编译了, ...

  3. Spring WebSocket教程(一)

    学习背景 很久以前就知道WebSocket,但那时不论是浏览器还是开发技术对它的支持都还很少.但是,Spring4突然发布,让我眼前一亮,Spring4直接支持WebSocket. 对于Spring我 ...

  4. Selenium (2) —— Selenium WebDriver + Grid2(101 Tutorial)

    Selenium (2) -- Selenium WebDriver + Grid2(101 Tutorial) jvm版本: 1.8.0_65 selenium版本: v2.48.0 (Standa ...

  5. python出现UnicodeEncodeError有可能产生的另一个原因

    在使用python中,我们都有可能遇到如下的错误: UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ...

  6. centos 7 升级/安装 git 2.7.3

      1.安装所需软件包 # yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel # yum instal ...

  7. tabs 标签样式

    http://www.jq22.com/jquery-info17973 http://www.jq22.com/demo/elementTab201801262311/ 插件描述:基于element ...

  8. Graph-DFS-图的深度优先遍历

    #include <iostream> using namespace std; /* 5 5 1 2 1 3 1 5 2 4 3 5 1 2 4 3 5 ---------------- ...

  9. php curl_multi系列函数实现多线程抓取网页

    最近几天在做一个多搜索引擎关键字排名查询工具,用于及时方便的了解关键词在各大搜索引擎的排名. 在抓取360搜索的时候,发现360搜索每页只支持显示10个搜索结果,如果想获取100个搜索结果数据,就得搜 ...

  10. Excel查看某列的重复值

    例如: 当查看的是B列的重复值时:=IF(COUNTIF(B:B,B1)>1,"重复","")