• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > 详解C#中的Async和Await用法

详解C#中的Async和Await用法

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c语言32关键字详解,c语言链表详解,c语言指针详解,c语言题库及详解答案,c语言关键字详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

 这篇文章由Filip Ekberg为DNC杂志编写。

自跟随着.NET 4.5 及Visual Studio 2012的C# 5.0起,我们能够使用涉及到async和await关键字的新的异步模式。有很多不同观点认为,比起以前我们看到的,它的可读性和可用性是否更为突出。我们将通过一个例子来看下它跟现在的怎么不同。

线性代码vs非线性代码

大部分的软件工程师都习惯用一种线性的方式去编程,至少这是他们开始职业生涯时就被这样教导。当一个程序使用线性方式去编写,这意味着它的源代码读起来有的像Figure 1展示的。这就是假设有一个适当的订单系统会帮助我们从某些地方去取一批订单。

2015713100246385.png (400×432)

 即使文章从左或从由开始,人们还是习惯于从上到下地阅读。如果我们有某些东西影响到了这个内容的顺序,我们将会感到困惑同时在这上面比实际需要的事情上花费更多努力。基于事件的程序通常拥有这些非线性的结构。


基于事件系统的流程是这样的,它在某处发起一个调用同时期待结果通过一个触发的时间传递,Figure 2 展示的很形象的表达了这点。初看这两个序列似乎不是很大区别,但如果我们假设GetAllOrders返回空,我们检索订单列表就没那么直接了当了。

不看实际的代码,我们认为线性方法处理起来更加舒服,同时它更少的有出错的倾向。在这种情况下,错误可能不是实际的运行时错误或者编译错误,但是在使用上的错误;由于缺乏明朗。


基于事件的方法有一个很大的优势;它让我们使用基于事件的异步模式更为一致。

2015713100321237.png (600×332)

 在你看到一个方法的时候,你会想去弄明白这方法的目的。这意味着如果你有一个叫ReloadOrdersAndRefreshUI的方法,你想去弄明白这些订单从哪里载入,怎样把它加到UI,当这方法结束的时候会发生什么。在基于事件的方法里,这很难如愿以偿。

另外得益于这的是,只要在我们出发LoadOrdersCompleted事件时,我们能够在GetAllOrders里写异步代码,返回到调用线程去。

介绍一个新的模式

让 我们假设我们在自己的系统上工作,系统使用上面提到过的OrderHandler以及实际实现是使用一个线性方法。为了模拟一小部分的真是订单系统,OrderHandler和Order如下:
 

class Order
{
  public string OrderNumber { get; set; }
  public decimal OrderTotal { get; set; }
  public string Reference { get; set; }
}
class OrderHandler
{
  private readonly IEnumerable<Order> _orders;
  public OrderHandler()
  {
    _orders = new[]
        {
          new Order {OrderNumber = "F1", OrderTotal = 100, Reference = "Filip"},
          new Order {OrderNumber = "F1", OrderTotal = 100, Reference = "Filip"}
        };
  }
  public IEnumerable<Order> GetAllOrders()
  {
    return _orders;
  }
}
</div>

因为我们在例子里不使用真是的数据源,我们需要让它有那么一点更为有趣的。由于这是关于异步编程的,我们想要在一个异步的方式中请求一些东西。为了模拟这个,我们简单的加入:
 

System.Threading.ManualResetEvent(false).WaitOne(2000) in GetAllOrders:
public IEnumerable<Order> GetAllOrders()
{
  System.Threading.ManualResetEvent(false).WaitOne(2000);
  return _orders;
}
</div>


这里我们不用Thread.Sleep的原因是这段代码将会加入到Windows8商店应用程序。这里的目的是在这里我们将会为我们的加载订单列表的Windows8商店应用程序放置一个可以按的按钮。然后,我们可以比较下用户体验和在之前加入的异步代码。

如果你已经创建了一个空的Windows商店应用程序项目,你可以加入如下的XAML到你的MainPage.xml:

 

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
  <Grid.RowDefinitions>
    <RowDefinition Height="140"/>
    <RowDefinition Height="*"/>
  </Grid.RowDefinitions>
 
  <TextBlock x:Name="pageTitle" Margin="120,0,0,0" Text="Order System" Style="{StaticResource PageHeaderTextStyle}" Grid.Column="1" IsHitTestVisible="false"/>
  <StackPanel Grid.Row="1" Margin="120,50,0,0">
    <TextBlock x:Name="Information" />
    <ProgressBar x:Name="OrderLoadingProgress" HorizontalAlignment="Left" Foreground="White" Visibility="Collapsed" IsIndeterminate="True" Width="100">
      <ProgressBar.RenderTransform>
        <CompositeTransform ScaleX="5" ScaleY="5" />
      </ProgressBar.RenderTransform>
    </ProgressBar>
    <ListView x:Name="Orders" DisplayMemberPath="OrderNumber" />
  </StackPanel>
  <AppBar VerticalAlignment="Bottom" Grid.Row="1">
    <Button Content="Load orders" x:Name="LoadOrders" Click="LoadOrders_Click" />
  </AppBar>
</Grid>
</div>

在我们的程序能跑之前,我们还需要在代码文件里加入一些东西:
 

public MainPage()
{
  this.InitializeComponent();
 
  Information.Text = "No orders have been loaded yet.";
}
private void LoadOrders_Click(object sender, RoutedEventArgs e)
{
  OrderLoadingProgress.Visibility = Visibility.Visible;
  var orderHandler = new OrderHandler();
  var orders = orderHandler.GetAllOrders();
  OrderLoadingProgress.Visibility = Visibility.Collapsed;
}
</div>

这会带给我们一个挺好看的应用程序,当我们在Visual Studio 2012的模拟器上运行的时候看起来就像这样:

2015713100358213.png (600×371)

看下底部的应用程序工具栏, 通过按这个在右手边的菜单的图标进入基本的触摸模式,然后从下往上刷。
 现在当你按下加载订单按钮的时候,你会注意到你看不到进度条同时按钮保持在被按下状态2秒。这是由于我们把应用程序锁定了。

以前我们可以通过在一个BackgroundWorker里封装代码来解决问题。当完成的时候,它会在我们为改变UI而已调用的委托中出发一个事件。这是一种非线性的方法,但往往会把代码的可读性搞得糟糕。在一个非WinRT的订单应用程序,使用BackgroundWorker应该看起来像这样:
 

public sealed partial class MainPage : Page
{
  private BackgroundWorker _worker = new BackgroundWorker();
  public MainPage()
  {
    InitializeComponent();
 
    _worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
    _worker.DoWork += WorkerDoWork;
  }
 
  void WorkerDoWork(object sender, DoWorkEventArgs e)
  {
    var orderHandler = new OrderHandler();
    var orders = orderHandler.GetAllOrders();
  }
 
  private void LoadOrders_Click(object sender, RoutedEventArgs e)
  {
    OrderLoadingProgress.Visibility = Visibility.Visible;
    _worker.RunWorkerAsync();
  }
 
  void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
    Dispatcher.BeginInvoke(new Action(() =>
    {
      // Update the UI
      OrderLoadingProgress.Visibility = Visibility.Collapsed;
    }));
  }
}
</div>

BackgroundWorker由于基于事件的异步性而被认识,这种模式叫做基于事件异步模式(EAP)。这往往会使代码比以前更乱,同时,由于它使用非线性方式编写,我们的脑袋要花一段事件才能对它有一定的概念。


但在WinRT中没有BackgroundWorker,所以我们必须适应新的线性方法,这也是一个好的事情!

我们对此的解决方法是适应.NET4.5引入的新的模式,async 与 await。当我们使用async 和 await,就必须同时使用任务并行库(TPL)。原则是每当一个方法需要异步执行,我们就给它这个标记。这意味着该方法将带着一些我们等待的东西返回,一个继续点。继续点段所在位置的标记,是由‘awaitable'的标记指明的,此后我们请求等待任务完成。


基于原始代码,没有BackgroundWorker的话我们只能对click处理代码做一些小的改变,以便它能应用于异步的方式。首先我们需要标记该方法为异步的,这简单到只需将关键字加到方法签名:
 

private async void LoadOrders_Click(object sender, RoutedEventArgs e)
</div>

同时使用async和void时需要很小

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 详解C#中三个关键字params,Ref,out
  • 详解三种C#实现数组反转方式
  • 详解C# 利用反射根据类名创建类的实例对象
  • 详解C#用new和override来实现抽象类的重写区别
  • 详解C#把DataTable中数据一次插入数据库的方法
  • 详解c# 类的构造方法
  • 详解C#多线程之线程同步
  • 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿
  • 详解C#中的委托
  • 详解C#中的out和ref

相关文章

  • 2017-05-28C#聊天程序服务端与客户端完整实例代码
  • 2017-05-28设置C#窗体程序只能启动一次
  • 2017-05-28WinForm实现自定义右下角提示效果的方法
  • 2017-05-28C#中哈希表(HashTable)用法实例详解(添加/移除/判断/遍历/排序等)
  • 2017-05-28浅析泛型类接口定义
  • 2017-05-28c#中DateTime.Now函数的使用详解
  • 2017-05-28C#把数组中的某个元素取出来放到第一个位置的实现方法
  • 2017-05-28C# 委托(delegate) 的小例子
  • 2017-05-28c#和javascript函数相互调用示例分享
  • 2017-05-28C#获得MAC地址(网卡序列号)的实现代码

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C#实现的ZPL条码打印类完整实例
    • C#编程和Visual Studio使用技巧(上)
    • C#中线程同步对象的方法分析
    • C#中Invoke 和 BeginInvoke 的真正涵义
    • 解析C#设计模式编程中适配器模式的实现
    • c#实现摄像头拍照功能示例
    • C#实现把彩色图片灰度化代码分享
    • C#中进程的挂起与恢复
    • c#数组详解
    • C#实现12306自动登录的方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有