20.1 什么是异步编程异步编程就是把耗时的操作放进一个单独的线程中进行处理。

20.2 同步方式存在的问题

 
  1. namespace 异步编程
  2. {
  3. public partial class Form1 : Form
  4. {
  5. public Form1()
  6. {
  7. InitializeComponent();
  8. txbUrl.Text = "http://dldir1.qq.com/qqfile/qq/QQ8.7/19113/QQ8.7.exe";
  9. }
  10. private void btnDownLoad_Click(object sender, EventArgs e)
  11. {
  12. rtbState.Text = "下载中.....";
  13. if (txbUrl.Text == string.Empty)
  14. {
  15. MessageBox.Show("请先输入下载地址!");
  16. return;
  17. }
  18. DownLoadFileSync(txbUrl.Text.Trim());
  19. }
  20. public void DownLoadFileSync(string url)
  21. {
  22. int BufferSize = 2084;
  23. byte[] BufferRead = new byte[BufferSize];
  24. string savePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\我的QQ.exe";
  25. FileStream fileStream = null;
  26. HttpWebResponse myWebResponse = null;
  27. if (File.Exists(savePath))
  28. {
  29. File.Delete(savePath);
  30. }
  31. fileStream = new FileStream(savePath, FileMode.OpenOrCreate);
  32. try
  33. {
  34. HttpWebRequest myHTTpWebRequest = (HttpWebRequest) WebRequest.Create(url);
  35. if (myHTTpWebRequest != null)
  36. {
  37. myWebResponse = (HttpWebResponse) myHTTpWebRequest.GetResponse();
  38. Stream responseStream = myWebResponse.GetResponseStream();
  39. int readSize = responseStream.Read(BufferRead, 0, BufferSize);
  40. while (readSize > 0)
  41. {
  42. fileStream.Write(BufferRead, 0, readSize);
  43. readSize = responseStream.Read(BufferRead, 0, BufferSize);
  44. }
  45. rtbState.Text = "文件下载完成,文件大小为:" + fileStream.Length + "下载路径为:" + savePath;
  46. }
  47. }
  48. catch (Exception ex)
  49. {
  50. rtbState.Text = "下载异常,异常信息为:" + ex.Message;
  51. }
  52. finally
  53. {
  54. if (myWebResponse != null)
  55. {
  56. myWebResponse.Close();
  57. }
  58. if (fileStream !=null)
  59. {
  60. fileStream.Close();
  61. }
  62. }
  63. }
  64. }
  65. }
虽然完成了文件下载功能,但却带来不好的用户体验,
点“下载”按钮后,程序处于“假死”状态。而且,“下载中....”也没有显示在界面中。
主线程忙于执行下载操作,无法空出时间来绘制窗体,导致在下载过程中出现“假死”现象。
异步编程可以很好的解决这个问题。

20.3 异步编程模型——APM(.NET不推荐)

         APM 是 Asynchronous Programming Mode (异步编程模式)的缩写。(在.NET Framework 4 和更早的版本中
        它允许程序用更少的线程去执行更多的操作。
        要分辨某个类是否实现异步编程模式,主要看该类是否实现了返回类型为 IAsyncResult 接口的 Beginxxx 和 Endxxx 方法。

1.Beginxxx 方法——开始执行异步操作

       在要获取文件中内容时,通常使用 FileStream 的同步方法 Read 进行读取,定义:
public abstract int Read(byte[] array, int offset, int count);
       该方法从文件流中读取字节块,然后将该数据写入给定的字节数组 array 中。这里 array 表示读取的字节块要被写入的地方, offset 表示从文件流读取字节的开始位置, count 表示最多读取的字节数。
       读取大文件时,调用 Read 方法会阻塞UI线程,导致文件没有读取前窗体无法响应。为了解决这个情况,.NET1.0就提出了异步编程模型,并为 FileStream 类提供了异步模型方法,即 BeginRead 方法。该方法会异步执行读取,并返回 IAsyncResult 接口的对象(该对象存储异步操作信息)。
public virtual IAsyncResult BeginRead(
byte[] buffer,
int offset,
int count,
AsyncCallback callback,
object state
)

该方法前面3个参数和同步方法 Read 一致,后两个参数 callback 和 state 则不同。

callbackType: System.AsyncCallback

异步操作完成后需要回调的方法,该方法必须匹配 AsyncCallback委托类型。

stateType: System.Object

传递给回调方法的对象,在回调方法中,可以查询 IAsyncResult 接口的 AsyncState 属性来读取该对象。

2.Endxxx 方法 ——结束异步操作

调用完 Beginxxx 方法后,还需要调用 Endxxx 方法来获取操作返回的结果。
Endxxx 返回的类型与同步方法相同,如 FileStream 的 EndRead 方法会返回一个 Int32 类型,代表从文件流中实际读取的字节数。
 
APM给出了4种方式来访问异步操作所得到的结果。
  1. 在调用 Beginxxx 方法的线程上调用 Endxxx 方法来得到异步操作的结果。然而这种方式会阻塞调用线程,使其一直挂起,直至操作完成。

  2. 在调用 Beginxxx 方法的线程查询 IAsyncResult 的 AsyncWaitHandle 属性,从而得到 WaitHandle 对象,接着调用该对象 WaitOne 方法来堵塞线程并等待操作完成,最后调用 Endxxx 方法获得操作结果。

  3. 在调用 Beginxxx 方法的线程上循环查询 IAsyncResult 的 IsComplete 属性,操作完成后调用 Endxxx 方法获得操作结果。

  4. 使用 AsyncCallback 委托来指定操作完成要调用的方法,在回调方法中调用 Endxxx 方法来获得异步操作返回的结果。

上面4种,前3种会堵塞调用线程。

第1种方式:

  1. public void DownLoadFileSync(string url)

  2. {

  3. int BufferSize = 2084;

  4. byte[] BufferRead = new byte[BufferSize];

  5. string savePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\我的QQ.exe";

  6. FileStream fileStream = null;

  7. HttpWebResponse myWebResponse = null;

  8. if (File.Exists(savePath))

  9. {

  10. File.Delete(savePath);

  11. }

  12. fileStream = new FileStream(savePath, FileMode.OpenOrCreate);

  13. try

  14. {

  15. HttpWebRequest myHTTpWebRequest = (HttpWebRequest) WebRequest.Create(url);

  16. if (myHTTpWebRequest != null)

  17. {

  18. //myWebResponse = (HttpWebResponse)myHTTpWebRequest.GetResponse();

  19. IAsyncResult result = myHTTpWebRequest.BeginGetResponse(null, null);//异步请求

  20. myWebResponse = (HttpWebResponse)myHTTpWebRequest.EndGetResponse(result);

  21. Stream responseStream = myWebResponse.GetResponseStream();

  22. int readSize = responseStream.Read(BufferRead, 0, BufferSize);

  23. while (readSize > 0)

  24. {

  25. fileStream.Write(BufferRead, 0, readSize);

  26. readSize = responseStream.Read(BufferRead, 0, BufferSize);

  27. }

  28. rtbState.Text = "文件下载完成,文件大小为:" + fileStream.Length + "下载路径为:" + savePath;

  29. }

  30. }

  31. catch (Exception ex)

  32. {

  33. rtbState.Text = "下载异常,异常信息为:" + ex.Message;

  34. }

  35. finally

  36. {

  37. if (myWebResponse != null)

  38. {

  39. myWebResponse.Close();

  40. }

  41. if (fileStream !=null)

  42. {

  43. fileStream.Close();

  44. }

  45. }

  46. }

DownLoadFileSync 方法通过调用 BeginGetResponse 方法来异步请求资源,执行该方法后立即返回UI线程。UI线程继续执行代码,遇到 EndGetResponse 方法,此方法堵塞UI线程,使得效果和同步方法实现一样。

  1. namespace 异步编程

  2. {

  3. public partial class Form1 : Form

  4. {

  5. public Form1()

  6. {

  7. InitializeComponent();

  8. txbUrl.Text = "http://dldir1.qq.com/qqfile/qq/QQ8.7/19113/QQ8.7.exe";

  9. }

  10. private delegate string AsyncMethodCaller(string fileurl);

  11. private SynchronizationContext sc;

  12. private void btnDownLoad_Click(object sender, EventArgs e)

  13. {

  14. rtbState.Text = "下载中.....";

  15. btnDownLoad.Enabled = false;

  16. if (txbUrl.Text == string.Empty)

  17. {

  18. MessageBox.Show("请先输入下载地址!");

  19. return;

  20. }

  21. //DownLoadFileSync(txbUrl.Text.Trim());

  22. sc = SynchronizationContext.Current;

  23. AsyncMethodCaller methodCaller = new AsyncMethodCaller(DownLoadFileSync);

  24. methodCaller.BeginInvoke(txbUrl.Text.Trim(), GetResult, null);

  25. }

  26. private void GetResult(IAsyncResult result)

  27. {

  28. AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;

  29. string returning = caller.EndInvoke(result);

  30. sc.Post(ShowState, returning);

  31. }

  32. private void ShowState(object result)

  33. {

  34. rtbState.Text = result.ToString();

  35. btnDownLoad.Enabled = true;

  36. }

  37. public string DownLoadFileSync(string url)

  38. {

  39. int BufferSize = 2084;

  40. byte[] BufferRead = new byte[BufferSize];

  41. string savePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\我的QQ.exe";

  42. FileStream fileStream = null;

  43. HttpWebResponse myWebResponse = null;

  44. if (File.Exists(savePath))

  45. {

  46. File.Delete(savePath);

  47. }

  48. fileStream = new FileStream(savePath, FileMode.OpenOrCreate);

  49. try

  50. {

  51. HttpWebRequest myHTTpWebRequest = (HttpWebRequest)WebRequest.Create(url);

  52. if (myHTTpWebRequest != null)

  53. {

  54. myWebResponse = (HttpWebResponse)myHTTpWebRequest.GetResponse();

  55. Stream responseStream = myWebResponse.GetResponseStream();

  56. int readSize = responseStream.Read(BufferRead, 0, BufferSize);

  57. while (readSize > 0)

  58. {

  59. fileStream.Write(BufferRead, 0, readSize);

  60. readSize = responseStream.Read(BufferRead, 0, BufferSize);

  61. }

  62. }

  63. return  string.Format("文件下载完成,文件大小为:" + fileStream.Length + "下载路径为:" + savePath);

  64. }

  65. catch (Exception ex)

  66. {

  67. return  string.Format("下载异常,异常信息为:" + ex.Message);

  68. }

  69. finally

  70. {

  71. if (myWebResponse != null)

  72. {

  73. myWebResponse.Close();

  74. }

  75. if (fileStream != null)

  76. {

  77. fileStream.Close();

  78. }

  79. }

  80. }

  81. }

  82. }

20.4 异步编程模型——EAP(.NET不推荐)

APM同样存在一些明显的问题,如不支持对异步操作的取消以及不能提供下载进度报告等。

微软.NET2.0发布提出了一个新的异步编程模式——基于事件的异步模式,EAP(Event-based Asynchronous Pattern)。

实现EPA的类具有一个或多个以 Async 为后缀的方法,以及对应的 Completed 事件,并且这些类支持异步方法的取消和进度报告。在.NET类库中只有部分类实现了EPA,共17个。

System.Object的派生类型:

  System.Activies.WorkflowInvoke  

  System.Deployment.Application.ApplicationDeployment

  System.Deployment.Application.InPlaceHosingManager

  System.Net.Mail.SmtpClient

  System.Net.PeerToPeer.PeerNameResolver

  System.Net.PeerToPeer.Collaboration.ContactManager

  System.Net.PeerToPeer.Collaboration.Peer

  System.Net.PeerToPeer.Collaboration.PeerContact

  System.Net.PeerToPeer.Collaboration.PeerNearMe

  System.ServiceModel.Activities.WorkflowControlClient

  System.ServiceModel.Discovery.AnnoucementClient

  System.ServiceModel.Discovery.DiscoveryClient

System.ComponentModel.Component的派生类型:

System.ComponentModel.BackgroundWorker

System.Media.SoundPlay

System.Net.WebClient

System.Net.NetworkInformation.Ping

System.Windows.Forms.PictureBox(继承于Control类,Control类派生于Component类)

使用最多的莫过于 BackgroundWorker 类了,该类经常被用于实现网络文件下载功能。

BackgroundWorker类

 

公共属性

 

属性名

说明

CancellationPending

获取一个值,指示应用程序是否已请求取消后台操作

IsBusy

获取一个值,指示 BackgroundWorker 是否正在运行异步操作。

WorkReportsProgress

获取或设置一个值,该值指示 BackgroundWorker 能否报告进度更新。

WorkerSupportsCancellation

获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。

公共方法

 

名称

说明

CancelAsync

请求取消挂起的后台操作。

ReportProgress

引发 ProgressChanged 事件(官方这样解释我就要信?)

RunWorkerAsync

开始执行后台操作。

公共事件

 

名称

说明

DoWork

调用 RunWorkerAsync 时发生(官方是这么解释的,你想知道为什么调用RunWorkerAsync方法就会触发DoWork事件吗?

ProgressChanged

调用ReportProgress时发生(官方是这么解释的,你想知道为什么调用ReportProgress方法就会触发ProgressChanged事件吗?)

RunWorkerCompleted

当后台操作已完成、被取消或引发异常时发生。

 
  1. public partial class Form1 : Form

  2. {

  3. public int DownloadSize = 0;

  4. public string downloadPath = null;

  5. long totalSize = 0;

  6. const int BufferSize = 2048;

  7. byte[] BufferRead = new byte[BufferSize];

  8. FileStream filestream = null;

  9. HttpWebResponse myWebResponse = null;

  10. public Form1()

  11. {

  12. InitializeComponent();

  13. string url = "http://dldir1.qq.com/qqfile/qq/QQ8.7/19113/QQ8.7.exe";

  14. txbUrl.Text = url;

  15. this.btnPause.Enabled = false;

  16. GetTotalSize();

  17. downloadPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + Path.GetFileName(this.txbUrl.Text.Trim());

  18. if (File.Exists(downloadPath))

  19. {

  20. FileInfo fileInfo = new FileInfo(downloadPath);

  21. DownloadSize = (int)fileInfo.Length;

  22. progressBar1.Value = (int)((float)DownloadSize / (float)totalSize * 100);

  23. }

  24. // 使BackgroundWorker类支持ReportProgress和ReportProgress操作

  25. bgWorkerFileDownload.WorkerReportsProgress = true;

  26. bgWorkerFileDownload.WorkerSupportsCancellation = true;

  27. }

  28. private void btnDownLoad_Click(object sender, EventArgs e)

  29. {

  30. if (bgWorkerFileDownload.IsBusy != true)

  31. {

  32. bgWorkerFileDownload.RunWorkerAsync();

  33. filestream = new FileStream(downloadPath, FileMode.OpenOrCreate);

  34. filestream.Seek(DownloadSize, SeekOrigin.Begin);

  35. this.btnDownLoad.Enabled = false;

  36. this.btnPause.Enabled = true;

  37. }

  38. else

  39. {

  40. MessageBox.Show("正在执行操作,请稍后");

  41. }

  42. }

  43. private void btnPause_Click(object sender, EventArgs e)

  44. {

  45. if (bgWorkerFileDownload.IsBusy && bgWorkerFileDownload.WorkerSupportsCancellation == true)

  46. {

  47. bgWorkerFileDownload.CancelAsync(); // 取消下载操作

  48. }

  49. }

  50. private void bgWorkerFileDownload_DoWork(object sender, DoWorkEventArgs e)

  51. {

  52. BackgroundWorker bgworker = sender as BackgroundWorker;

  53. try

  54. {

  55. // Do the DownLoad operation

  56. // Initialize an HttpWebRequest object

  57. HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(txbUrl.Text.Trim());

  58. // If the part of the file have been downloaded,

  59. // The server should start sending data from the DownloadSize to the end of the data in the HTTP entity.

  60. if (DownloadSize != 0)

  61. {

  62. myHttpWebRequest.AddRange(DownloadSize);

  63. }

  64. // assign HttpWebRequest instance to its request field.

  65. myWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

  66. Stream responseStream = myWebResponse.GetResponseStream();

  67. int readSize = 0;

  68. while (true)

  69. {

  70. if (bgworker.CancellationPending == true)

  71. {

  72. e.Cancel = true;

  73. break;

  74. }

  75. readSize = responseStream.Read(BufferRead, 0, BufferRead.Length);

  76. if (readSize > 0)

  77. {

  78. DownloadSize += readSize;

  79. int percentComplete = (int)((float)DownloadSize / (float)totalSize * 100);

  80. filestream.Write(BufferRead, 0, readSize);

  81. // 报告进度,引发ProgressChanged事件的发生

  82. bgworker.ReportProgress(percentComplete);

  83. }

  84. else

  85. {

  86. break;

  87. }

  88. }

  89. }

  90. catch

  91. {

  92. throw;

  93. }

  94. }

  95. private void bgWorkerFileDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)

  96. {

  97. this.progressBar1.Value = e.ProgressPercentage;

  98. }

  99. private void bgWorkerFileDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

  100. {

  101. if (e.Error != null)

  102. {

  103. MessageBox.Show(e.Error.Message);

  104. myWebResponse.Close();

  105. }

  106. else if (e.Cancelled)

  107. {

  108. MessageBox.Show(String.Format("下载暂停,下载的文件地址为:{0}\n 已经下载的字节数为: {1}字节", downloadPath, DownloadSize));

  109. myWebResponse.Close();

  110. filestream.Close();

  111. filestream.Close();

  112. this.btnDownLoad.Enabled = true;

  113. this.btnPause.Enabled = false;

  114. }

  115. else

  116. {

  117. MessageBox.Show(String.Format("下载已完成,下载的文件地址为:{0},文件的总字节数为: {1}字节", downloadPath, totalSize));

  118. this.btnDownLoad.Enabled = false;

  119. this.btnPause.Enabled = false;

  120. myWebResponse.Close();

  121. filestream.Close();

  122. }

  123. }

  124. private void GetTotalSize() // 获得文件总大小

  125. {

  126. HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(txbUrl.Text.Trim());

  127. HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();

  128. totalSize = response.ContentLength;

  129. response.Close();

  130. }

  131. }

[你必须知道的异步编程]——基于事件的异步编程模式

http://www.cnblogs.com/zhili/archive/2013/05/11/EAP.html

20.5 异步编程模型——TAP

前2种模式在.NET中被标识为不推荐使用的实现方式。

在.NET 4.0中,微软提供更简单的异步方式——基于任务的异步模式,即TAP。

该模式主要使用 System.Threading.Tasks.Task和Task<T> 类来完成异步编程,相对于前面两种异步模式来讲,TAP使异步编程模式更加简单(因为这里我们只需要关注 Task 这个类的使用),同时TAP也是微软推荐使用的异步编程模式。

        基于任务的异步模式,只使用一个方法就能表示异步操作的开始和完成。只需要一个以 TaskAsync 为后缀的方法,通过向该方法传入 CancellationToken 参数,就可以完成异步编程了。而且还可以通过 IProgress<T> 接口来实现进度报告的功能。
 
 

20.6 C#5.0 中的 async 和 await

 
太大段代码,还是看看《C#本质论》18章 和《精通C#(第6版)》19章
 
 
 

《learning hard C#学习笔记》读书笔记(20)异步编程的更多相关文章

  1. 《Hands-On Machine Learning with Scikit-Learn&TensorFlow》读书笔记

    一 机器学习概览 机器学习的广义概念是:机器学习是让计算机具有学习的能力,无需进行明确编程. 机器学习的工程性概念是:计算机程序利用经验E学习任务T,性能是P,如果针对任务T的性能P随着经验E不断增长 ...

  2. 鸟哥Linux私房菜 基础学习篇读书笔记(10):Linux磁盘和文件系统管理(3)

    本文总结了Linux操作系统来管理我们的硬盘和文件系统需要使用命令.当我们在系统中增加一个硬盘驱动器.什么是我们需要去通过这个硬盘就可以真正使用步骤?下面步骤: (1)对磁盘进行分区,新建能够使用的分 ...

  3. 鸟哥的Linux私房菜 基础学习篇读书笔记(9):Linux磁盘与文件系统管理(2)

    上一篇文章主要从理论上分析了Linux的Ext2文件系统.这一篇主要解说怎样查看Linux的文件系统的容量以及解说Linux文件系统中的连接文件. 能够通过df和du命令来查看磁盘与文件夹的容量.df ...

  4. 人体和电脑的关系——鸟哥的LINUX私房菜基础学习篇读书笔记

    CUP=脑袋: 每个人会做的事情都不一样(指令集的差异),但主要都是通过脑袋来判断与控制身体各部分的行动 内存=脑袋中存放正在思考的数据区块: 在实际活动过程中,我们的脑袋需要有外界刺激的数据(例如光 ...

  5. Deep Learning 2_深度学习UFLDL教程:矢量化编程(斯坦福大学深度学习教程)

    1前言 本节主要是让人用矢量化编程代替效率比较低的for循环. 在前一节的Sparse Autoencoder练习中已经实现了矢量化编程,所以与前一节的区别只在于本节训练集是用MINIST数据集,而上 ...

  6. 人生效率手册:如何卓有成效地过好每一天--By张萌姐姐--读书笔记

    读书笔记:<人生效率手册>:如何卓有成效地过好每一天--By张萌姐姐... 整本书看完的感受: 这本书主要讲的是生活中我们需要给自己一个目标,然后通过自己的努力去实现这个目标,书中说的很多 ...

  7. 强化学习读书笔记 - 06~07 - 时序差分学习(Temporal-Difference Learning)

    强化学习读书笔记 - 06~07 - 时序差分学习(Temporal-Difference Learning) 学习笔记: Reinforcement Learning: An Introductio ...

  8. 【Deep Learning读书笔记】深度学习中的概率论

    本文首发自公众号:RAIS,期待你的关注. 前言 本系列文章为 <Deep Learning> 读书笔记,可以参看原书一起阅读,效果更佳. 概率论 机器学习中,往往需要大量处理不确定量,或 ...

  9. 阅读《LEARNING HARD C#学习笔记》知识点总结与摘要系列文章索引

    从发表第一篇文章到最后一篇文章,时间间隔有整整一个月,虽只有5篇文章,但每一篇文章都是我吸收<LEARNING HARD C#学习笔记>这本书的内容要点及网上各位大牛们的经验,没有半点废话 ...

随机推荐

  1. http://www.cnblogs.com/kissdodog/p/4159176.html

    想要自己一个人完成app,那么后台接口也必须自己动动手.不用担心,其实很简单的,给自己信心!下面就以登录注册为例,做一个api接口 首先在mac上搭建PHP环境,下载 MAMP Pro for Mac ...

  2. ASP.NET MVC Filter- 登录验证 【异步刷新列表视图】

    public class TAjaxListLoginValidateAttribute : FilterAttribute, IAuthorizationFilter { public void O ...

  3. juery实现贪吃蛇的游戏

    今天用juery做了一个贪吃蛇的游戏,代码比较简陋,不过作为这些天学习juery的成果,非常有成就感.另外关于代码内容如有雷同不胜荣幸. 更改了下 让头和身子的颜色不一样 这样好区分些,虽然还是不怎么 ...

  4. spring MVC mybatis dispacherServlet(源码解读)

    以下源码版本(4.2.0.RELEASE) dispacherServlet是servlet的实现类,是spring MVC的前端转发器,是spring MVC的核心. 那么它做了哪些事呢? 它主要做 ...

  5. 【学习笔记】Struts2 应用开发步骤

    1.在web.xml文件中定义核心Filter来拦截用户请求. <!-- 定义Struts 2的核心Filter --> <filter> <filter-name> ...

  6. jq添加数组

    var array=new Array(); array.push(值); //向数组中添加值 array.shift(值);//向数组中移除值

  7. Spark 官方文档(4)——Configuration配置

    Spark可以通过三种方式配置系统: 通过SparkConf对象, 或者Java系统属性配置Spark的应用参数 通过每个节点上的conf/spark-env.sh脚本为每台机器配置环境变量 通过lo ...

  8. scanf_s

    很多带“_s”后缀的函数是为了让原版函数更安全,传入一个和参数有关的大小值,避免引用到不存在的元素,有时hacker可以利用原版的不安全性黑掉系统 例如: ANSI C中没有scanf_s(),只有s ...

  9. ArrayList和HashSet的Contains()方法(转)

    来源: ArrayList和HashSet的Contains()方法 笔试题: package com.champion.test.exam; import java.util.ArrayList; ...

  10. Qt拖拽界面 (*.ui) 缩放问题及解决办法

    问题 使用Qt Designer 设计的界面,在缩放的时候不能随着主窗口一起缩放. 解决办法 之前遇到这个问题的时候,都是直接重写resizeEvent接口来实现的,在自动生成的Ui_Widget或U ...