接着上一篇,我们继续来优化。我们的 SkyParallelWebClient 可否支持切换“同步下载模式”和“异步下载模式”呢,好处是大量的代码不用改,只需要调用 skyParallelWebClient.StartAsync() 就开始异步下载,而改为 skyParallelWebClient.StartSync(); 就同步下载。如图:

同步下载:

异步下载:

1. 同步下载模式

直接贴代码了:

  1. public partial class Form1 : Form
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. }
  7.  
  8. private List<int> GetDownloadIds()
  9. {
  10. List<int> ids = new List<int>();
  11. for (int i = ; i <= ; i++)
  12. {
  13. ids.Add(i);
  14. }
  15. return ids;
  16. }
  17.  
  18. private void WhenAllDownloading()
  19. {
  20. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
  21. //禁用按钮
  22. EnableOrDisableButtons(false);
  23. }
  24.  
  25. private void EnableOrDisableButtons(bool enabled)
  26. {
  27. this.btnRunByHttpClient.Enabled = enabled;
  28. this.btnRunByWebClient.Enabled = enabled;
  29. }
  30.  
  31. private void WhenSingleDownloading(WhenSingleDownloadEventArgs eventArg)
  32. {
  33. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},剩余 {1} 个。编号 {2} 准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), eventArg.RemainingQueueCount, eventArg.CurrentDownloadEntry.Data));
  34. }
  35.  
  36. private void WhenSingleDownloaded(WhenSingleDownloadEventArgs eventArg)
  37. {
  38. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},剩余 {1} 个。编号 {2} 下载完毕...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), eventArg.RemainingQueueCount, eventArg.CurrentDownloadEntry.Data));
  39. }
  40.  
  41. private void WhenAllDownloaded()
  42. {
  43. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},下载完毕!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
  44. //启用按钮
  45. EnableOrDisableButtons(true);
  46. }
  47.  
  48. private async void btnRunByHttpClient_Click(object sender, EventArgs e)
  49. {
  50. //SkyHttpClient skyHttpClient = new SkyHttpClient();
  51. //try
  52. //{
  53. // WhenAllDownloading();
  54. // foreach (var id in GetDownloadIds())
  55. // {
  56. // bool singleDownloadSuccess = await TaskDemo101.RunByHttpClient(skyHttpClient, id);
  57. // WhenSingleDownloading(id);
  58. // }
  59. // WhenAllDownloaded();
  60. //}
  61. //catch (Exception ex)
  62. //{
  63. // MessageBox.Show(ex.Message, "Download Error!");
  64. //}
  65. }
  66.  
  67. private void btnRunByWebClient_Click(object sender, EventArgs e)
  68. {
  69. WhenAllDownloading();
  70. var ids = GetDownloadIds();
  71. List<DownloadEntry> downloadConfigs = new List<DownloadEntry>();
  72. Random rd = new Random();
  73. foreach (var id in ids)
  74. {
  75. downloadConfigs.Add(new DownloadEntry(TaskDemo101.GetRandomUrl(rd), TaskDemo101.GetSavedFileFullName(), id));
  76. }
  77. // 方案4(同步下载,需要启动另外一个线程)
  78. ThreadPool.QueueUserWorkItem(new WaitCallback(RunByWebClientCore), downloadConfigs);
  79. }
  80.  
  81. private void RunByWebClientCore(object state)
  82. {
  83. List<DownloadEntry> downloadConfigs = (List<DownloadEntry>)state;
  84. SkyParallelWebClient skyParallelWebClient = new SkyParallelWebClient(downloadConfigs, );
  85. skyParallelWebClient.SetMaximumForProgress += SkyParallelWebClient_SetMaximumForProgress;
  86. skyParallelWebClient.SetRealTimeValueForProgress += SkyParallelWebClient_SetRealTimeValueForProgress;
  87. skyParallelWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
  88. skyParallelWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
  89. skyParallelWebClient.WhenSingleDownloaded += SkyWebClient_WhenSingleDownloaded;
  90. skyParallelWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
  91. skyParallelWebClient.StartSync();
  92. }
  93.  
  94. private void SkyParallelWebClient_SetRealTimeValueForProgress(int realTimeValue)
  95. {
  96. this.progressBar1.Value = realTimeValue;
  97. }
  98.  
  99. private void SkyParallelWebClient_SetMaximumForProgress(int maximum)
  100. {
  101. this.progressBar1.Maximum = maximum;
  102. }
  103.  
  104. private void SkyWebClient_WhenDownloadingError(Exception ex)
  105. {
  106. MessageBox.Show("下载时出现错误: " + ex.Message);
  107. }
  108.  
  109. private void SkyWebClient_WhenSingleDownloading(WhenSingleDownloadEventArgs eventArg)
  110. {
  111. WhenSingleDownloading(eventArg);
  112. }
  113.  
  114. private void SkyWebClient_WhenSingleDownloaded(WhenSingleDownloadEventArgs eventArg)
  115. {
  116. WhenSingleDownloaded(eventArg);
  117. }
  118.  
  119. private void SkyWebClient_WhenAllDownloaded()
  120. {
  121. btnRunByWebClient.Text = "用 WebClient 开始下载";
  122. WhenAllDownloaded();
  123. }
  124.  
  125. }

运行截图:

2. 异步下载模式

直接贴代码了:

  1. public partial class Form1 : Form
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. }
  7.  
  8. private List<int> GetDownloadIds()
  9. {
  10. List<int> ids = new List<int>();
  11. for (int i = ; i <= ; i++)
  12. {
  13. ids.Add(i);
  14. }
  15. return ids;
  16. }
  17.  
  18. private void WhenAllDownloading()
  19. {
  20. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
  21. //禁用按钮
  22. EnableOrDisableButtons(false);
  23. }
  24.  
  25. private void EnableOrDisableButtons(bool enabled)
  26. {
  27. this.btnRunByHttpClient.Enabled = enabled;
  28. this.btnRunByWebClient.Enabled = enabled;
  29. }
  30.  
  31. private void WhenSingleDownloading(WhenSingleDownloadEventArgs eventArg)
  32. {
  33. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},剩余 {1} 个。编号 {2} 准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), eventArg.RemainingQueueCount, eventArg.CurrentDownloadEntry.Data));
  34. }
  35.  
  36. private void WhenSingleDownloaded(WhenSingleDownloadEventArgs eventArg)
  37. {
  38. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},剩余 {1} 个。编号 {2} 下载完毕...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), eventArg.RemainingQueueCount, eventArg.CurrentDownloadEntry.Data));
  39. }
  40.  
  41. private void WhenAllDownloaded()
  42. {
  43. this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},下载完毕!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
  44. //启用按钮
  45. EnableOrDisableButtons(true);
  46. }
  47.  
  48. private async void btnRunByHttpClient_Click(object sender, EventArgs e)
  49. {
  50. //SkyHttpClient skyHttpClient = new SkyHttpClient();
  51. //try
  52. //{
  53. // WhenAllDownloading();
  54. // foreach (var id in GetDownloadIds())
  55. // {
  56. // bool singleDownloadSuccess = await TaskDemo101.RunByHttpClient(skyHttpClient, id);
  57. // WhenSingleDownloading(id);
  58. // }
  59. // WhenAllDownloaded();
  60. //}
  61. //catch (Exception ex)
  62. //{
  63. // MessageBox.Show(ex.Message, "Download Error!");
  64. //}
  65. }
  66.  
  67. private void btnRunByWebClient_Click(object sender, EventArgs e)
  68. {
  69. WhenAllDownloading();
  70. var ids = GetDownloadIds();
  71. List<DownloadEntry> downloadConfigs = new List<DownloadEntry>();
  72. Random rd = new Random();
  73. foreach (var id in ids)
  74. {
  75. downloadConfigs.Add(new DownloadEntry(TaskDemo101.GetRandomUrl(rd), TaskDemo101.GetSavedFileFullName(), id));
  76. }
  77. //搜索: Parallel WebClient
  78. // 方案1
  79. //SkyWebClient skyWebClient = new SkyWebClient(downloadConfigs, this.progressBar1);
  80. //skyWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
  81. //skyWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
  82. //skyWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
  83. //skyWebClient.Start();
  84. // 方案2(代码已经调整,无法恢复)
  85. //ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncRunSkyParallelWebClient), downloadConfigs);
  86. // 方案3(异步下载,完美)
  87. SkyParallelWebClient skyParallelWebClient = new SkyParallelWebClient(downloadConfigs, );
  88. skyParallelWebClient.SetMaximumForProgress += SkyParallelWebClient_SetMaximumForProgress;
  89. skyParallelWebClient.SetRealTimeValueForProgress += SkyParallelWebClient_SetRealTimeValueForProgress;
  90. skyParallelWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
  91. skyParallelWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
  92. skyParallelWebClient.WhenSingleDownloaded += SkyWebClient_WhenSingleDownloaded;
  93. skyParallelWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
  94. skyParallelWebClient.StartSync();
  95. // 方案4(同步下载,需要启动另外一个线程)
  96. //ThreadPool.QueueUserWorkItem(new WaitCallback(RunByWebClientCore), downloadConfigs);
  97. }
  98.  
  99. private void RunByWebClientCore(object state)
  100. {
  101. List<DownloadEntry> downloadConfigs = (List<DownloadEntry>)state;
  102. SkyParallelWebClient skyParallelWebClient = new SkyParallelWebClient(downloadConfigs, );
  103. skyParallelWebClient.SetMaximumForProgress += SkyParallelWebClient_SetMaximumForProgress;
  104. skyParallelWebClient.SetRealTimeValueForProgress += SkyParallelWebClient_SetRealTimeValueForProgress;
  105. skyParallelWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
  106. skyParallelWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
  107. skyParallelWebClient.WhenSingleDownloaded += SkyWebClient_WhenSingleDownloaded;
  108. skyParallelWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
  109. skyParallelWebClient.StartSync();
  110. }
  111.  
  112. private void SkyParallelWebClient_SetRealTimeValueForProgress(int realTimeValue)
  113. {
  114. this.progressBar1.Value = realTimeValue;
  115. }
  116.  
  117. private void SkyParallelWebClient_SetMaximumForProgress(int maximum)
  118. {
  119. this.progressBar1.Maximum = maximum;
  120. }
  121.  
  122. private void SkyWebClient_WhenDownloadingError(Exception ex)
  123. {
  124. MessageBox.Show("下载时出现错误: " + ex.Message);
  125. }
  126.  
  127. private void SkyWebClient_WhenSingleDownloading(WhenSingleDownloadEventArgs eventArg)
  128. {
  129. WhenSingleDownloading(eventArg);
  130. }
  131.  
  132. private void SkyWebClient_WhenSingleDownloaded(WhenSingleDownloadEventArgs eventArg)
  133. {
  134. WhenSingleDownloaded(eventArg);
  135. }
  136.  
  137. private void SkyWebClient_WhenAllDownloaded()
  138. {
  139. btnRunByWebClient.Text = "用 WebClient 开始下载";
  140. WhenAllDownloaded();
  141. }
  142.  
  143. }

运行截图:

如上图:当打印了“下载完毕”后,仍然打印了许多日志,这是因为异步下载的回调是不定时的。为了避免这种情况,建议 WhenSingleDownloading 事件和 WhenSingleDownloaded 事件二选一,因为实在没有必要下载开始前和下载后都打印日志。我们再次修改代码后,得到如下图的日志。

日志是不是清晰了很多?一般下载完成,可以注册完成事件,事件里面不用打印日志,而做一些比如“修改数据库表记录的状态字段”等等。

3. 总结

SkyParallelWebClient 完整的代码如下:

  1. /// <summary>
  2. /// 设置进度条的最大值的事件处理
  3. /// </summary>
  4. /// <param name="maximum"></param>
  5. public delegate void SetMaximumForProgressEventHandler(int maximum);
  6.  
  7. /// <summary>
  8. /// 设置进度条的当前实时的值的事件处理
  9. /// </summary>
  10. /// <param name="maximum"></param>
  11. public delegate void SetRealTimeValueForProgressEventHandler(int realTimeValue);
  12.  
  13. /// <summary>
  14. /// 并行的 WebClient
  15. /// </summary>
  16. public class SkyParallelWebClient : SkyWebClientBase
  17. {
  18. ConcurrentQueue<DownloadEntry> OptionDataList = new ConcurrentQueue<DownloadEntry>(); //比如说:有 500 个元素
  19.  
  20. ConcurrentDictionary<WebClient, DownloadEntry> ProcessingTasks = new ConcurrentDictionary<WebClient, DownloadEntry>(); //当前运行中的
  21.  
  22. public event SetMaximumForProgressEventHandler SetMaximumForProgress;
  23. protected virtual void OnSetMaximumForProgress(int maximum)
  24. {
  25. if (SetMaximumForProgress != null)
  26. {
  27. SetMaximumForProgress(maximum);
  28. }
  29. }
  30.  
  31. public event SetRealTimeValueForProgressEventHandler SetRealTimeValueForProgress;
  32. protected virtual void OnSetRealTimeValueForProgress(int realTimeValue)
  33. {
  34. if (SetRealTimeValueForProgress != null)
  35. {
  36. SetRealTimeValueForProgress(realTimeValue);
  37. }
  38. }
  39.  
  40. public int ParallelCount { get; }
  41.  
  42. public bool IsCompleted { get; private set; }
  43.  
  44. public int Maximum { get;}
  45.  
  46. private static object lockObj = new object();
  47.  
  48. /// <summary>
  49. /// 构造函数
  50. /// </summary>
  51. /// <param name="downloadConfigs">要下载的全部集合,比如 N 多要下载的,N无限制</param>
  52. public SkyParallelWebClient(IEnumerable<DownloadEntry> downloadConfigs)
  53. :this(downloadConfigs, )
  54. {
  55.  
  56. }
  57.  
  58. /// <summary>
  59. /// 构造函数
  60. /// </summary>
  61. /// <param name="downloadConfigs">要下载的全部集合,比如 N 多要下载的,N无限制</param>
  62. /// <param name="parallelCount">单位内,并行下载的个数。切忌:该数字不能过大,否则可能很多文件因为 WebClient 超时,而导致乱文件(即:文件不完整)一般推荐 20 个左右</param>
  63. public SkyParallelWebClient(IEnumerable<DownloadEntry> downloadConfigs, int parallelCount)
  64. {
  65. if (downloadConfigs == null)
  66. {
  67. throw new ArgumentNullException("downloadConfigs");
  68. }
  69. this.ParallelCount = parallelCount;
  70. foreach (var item in downloadConfigs)
  71. {
  72. OptionDataList.Enqueue(item);
  73. }
  74. this.Maximum = OptionDataList.Count;
  75. System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue;
  76. OnSetMaximumForProgress(this.Maximum);
  77. }
  78.  
  79. /// <summary>
  80. /// 异步启动(备注:由于内部采用异步下载,所以方法不用加 Try 和返回值)
  81. /// </summary>
  82. public void StartAsync()
  83. {
  84. StartAsyncCore();
  85. }
  86.  
  87. protected void StartAsyncCore()
  88. {
  89. if (OptionDataList.Count <= )
  90. {
  91. SetIsCompletedTrue();
  92. return;
  93. }
  94. while (OptionDataList.Count > && ProcessingTasks.Count <= ParallelCount)
  95. {
  96. DownloadEntry downloadEntry;
  97. if (!OptionDataList.TryDequeue(out downloadEntry))
  98. {
  99. break;
  100. }
  101. DownloadFileAsync(downloadEntry);
  102. OnWhenSingleDownloading(new WhenSingleDownloadEventArgs
  103. {
  104. CurrentDownloadEntry = downloadEntry,
  105. RemainingQueueCount = OptionDataList.Count
  106. });
  107. }
  108. }
  109.  
  110. /// <summary>
  111. /// 同步启动
  112. /// </summary>
  113. public void StartSync()
  114. {
  115. StartSyncCore();
  116. }
  117.  
  118. /// <summary>
  119. /// 同步启动
  120. /// </summary>
  121. public void StartSync(WebClient webClient)
  122. {
  123. StartSyncCore(webClient);
  124. }
  125.  
  126. protected void StartSyncCore()
  127. {
  128. using (WebClient webClient = new WebClient())
  129. {
  130. StartSyncCore(webClient);
  131. }
  132. }
  133.  
  134. protected void StartSyncCore(WebClient webClient)
  135. {
  136. while (OptionDataList.Count > )
  137. {
  138. DownloadEntry downloadEntry;
  139. if (!OptionDataList.TryDequeue(out downloadEntry))
  140. {
  141. break;
  142. }
  143. OnWhenSingleDownloading(new WhenSingleDownloadEventArgs
  144. {
  145. CurrentDownloadEntry = downloadEntry,
  146. RemainingQueueCount = OptionDataList.Count
  147. });
  148. DownloadFile(downloadEntry, webClient);
  149. OnWhenSingleDownloaded(new WhenSingleDownloadEventArgs
  150. {
  151. CurrentDownloadEntry = downloadEntry,
  152. RemainingQueueCount = OptionDataList.Count
  153. });
  154. }
  155. SetIsCompletedTrue();
  156. }
  157.  
  158. protected void SetIsCompletedTrue()
  159. {
  160. if (!IsCompleted)
  161. {
  162. lock (lockObj)
  163. {
  164. if (!IsCompleted)
  165. {
  166. OnSetRealTimeValueForProgress();//表示已经完成
  167. OnWhenAllDownloaded();
  168. IsCompleted = true;
  169. }
  170. }
  171. }
  172. }
  173.  
  174. private void DownloadFileAsync(DownloadEntry downloadEntry)
  175. {
  176. using (WebClient webClient = new WebClient())
  177. {
  178. webClient.Proxy = null;
  179. webClient.DownloadFileCompleted += WebClient_DownloadFileCompleted;
  180. webClient.DownloadFileAsync(new Uri(downloadEntry.Url), downloadEntry.Path);
  181. ProcessingTasks.TryAdd(webClient, downloadEntry);
  182. }
  183. }
  184.  
  185. private void DownloadFile(DownloadEntry downloadEntry)
  186. {
  187. using (WebClient webClient = new WebClient())
  188. {
  189. DownloadFile(downloadEntry, webClient);
  190. }
  191. }
  192.  
  193. private void DownloadFile(DownloadEntry downloadEntry, WebClient webClient)
  194. {
  195. try
  196. {
  197. webClient.Proxy = null;
  198. webClient.DownloadFile(new Uri(downloadEntry.Url), downloadEntry.Path);
  199. }
  200. catch (Exception ex)
  201. {
  202. OnWhenDownloadingError(ex);
  203. }
  204. }
  205.  
  206. private void WebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
  207. {
  208. WebClient webClient = (WebClient)sender;
  209. DownloadEntry downloadEntry;
  210. if (ProcessingTasks.TryRemove(webClient, out downloadEntry))
  211. {
  212. OnWhenSingleDownloaded(new WhenSingleDownloadEventArgs
  213. {
  214. CurrentDownloadEntry = downloadEntry,
  215. RemainingQueueCount = OptionDataList.Count
  216. });
  217. try
  218. {
  219. int realTimeValue = (this.Maximum - OptionDataList.Count) * / this.Maximum;
  220. OnSetRealTimeValueForProgress(realTimeValue); //表示单个已经完成
  221. }
  222. catch (Exception)
  223. {
  224.  
  225. }
  226. }
  227. StartAsyncCore();
  228. }
  229. }

谢谢浏览!

一个简单的利用 WebClient 异步下载的示例(五)(完结篇)的更多相关文章

  1. 一个简单的利用 WebClient 异步下载的示例(三)

    继续上一篇 一个简单的利用 WebClient 异步下载的示例(二) 后,继续优化它. 1. 直接贴代码了: DownloadEntry: public class DownloadEntry { p ...

  2. 一个简单的利用 WebClient 异步下载的示例(二)

    继上一篇 一个简单的利用 WebClient 异步下载的示例(一) 后,我想把核心的处理提取出来,成 SkyWebClient,如下: 1. SkyWebClient 该构造函数中 downloadC ...

  3. 一个简单的利用 WebClient 异步下载的示例(一)

    继上一篇文章 一个简单的利用 HttpClient 异步下载的示例 ,我们知道不管是 HttpClient,还算 WebClient,都不建议每次调用都 new HttpClient,或 new We ...

  4. 一个简单的利用 WebClient 异步下载的示例(四)

    接上一篇,我们继续优化它. 1. DownloadEntry 类 public class DownloadEntry { public string Url { get; set; } public ...

  5. 一个简单的利用 HttpClient 异步下载的示例

    可能你还会喜欢 一个简单的利用 WebClient 异步下载的示例  ,且代码更加新. 1. 定义自己的 HttpClient 类. using System; using System.Collec ...

  6. VC6下OpenGL 开发环境的构建外加一个简单的二维网络棋盘绘制示例

    一.安装GLUT 工具包 GLUT 不是OpenGL 所必须的,但它会给我们的学习带来一定的方便,推荐安装. Windows 环境下的GLUT 本地下载地址:glut-install.zip(大小约为 ...

  7. 一个简单的AXIS远程调用Web Service示例

    我们通常都将编写好的Web Service发布在Tomcat或者其他应用服务器上,然后通过浏览器调用该Web Service,返回规范的XML文件.但是如果我们不通过浏览器调用,而是通过客户端程序调用 ...

  8. Java RMI 实现一个简单的GFS(谷歌文件系统)——背景与设计篇

    目录 背景 系统设计 1. 系统功能 2. Master组件 2.1 命名空间 2.2 心跳机制 2.3 故障恢复和容错机制 3. ChunkServer组件 3.1 本地存储 3.2 内存命中机制 ...

  9. 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(三)(错误整理篇)

    使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二) 以上两篇已经把流 ...

随机推荐

  1. laravel中视图的基本使用(七)

    laravel中的视图默认保存在 resources\views 目录下.在控制器中,我们通常使用 view() 方法返回一个视图文件. <?php namespace App\Http\Con ...

  2. go-goroutine 和 channel

    goroutine 和 channel goroutine-看一个需求 需求:要求统计 1-9000000000 的数字中,哪些是素数? 分析思路: 1) 传统的方法,就是使用一个循环,循环的判断各个 ...

  3. java基础(12):构造方法、this、super

    1. 构造方法 我们对封装已经有了基本的了解,接下来我们来看一个新的问题,依然以Person为例,由于Person中的属性都被private了,外界无法直接访问属性,必须对外提供相应的set和get方 ...

  4. JDK1.8新特性——Collector接口和Collectors工具类

    JDK1.8新特性——Collector接口和Collectors工具类 摘要:本文主要学习了在Java1.8中新增的Collector接口和Collectors工具类,以及使用它们在处理集合时的改进 ...

  5. DataGridView中的rows.Count比实际行数多1的原因以及解决办法

    场景 DataGridView怎样实现添加.删除.上移.下移一行: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10281414 ...

  6. VS中怎样对C#项目进行单元测试

    场景 SpringBoot+Junit在IDEA中实现查询数据库的单元测试: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/927 ...

  7. CSS3 2D变形 transform---移动 translate(x, y), 缩放 scale(x, y), 旋转 rotate(deg), transform-origin, 倾斜 skew(deg, deg)

    transform是CSS3中具有颠覆性的特征之一,可以实现元素的位移.旋转.倾斜.缩放,甚至支持矩阵方式,配合过渡和即将学习的动画知识,可以取代大量之前只能靠Flash才可以实现的效果. 变形转换 ...

  8. 2019年上半年收集到的人工智能GAN干货文章

    2019年上半年收集到的人工智能GAN干货文章 GAN简介及其常见应用 训练GAN,你应该知道的二三事 了解生成对抗网络(GAN) CosmoGAN:训练GAN,让AI寻找宇宙中的暗物质 关于GAN的 ...

  9. sqlserver查询是否阻塞

    查询当前正在执行的语句 SELECT der.[session_id],der.[blocking_session_id], sp.lastwaittype,sp.hostname,sp.progra ...

  10. Flask Rest接口

    Flask适用于简单的接口请求 安装 pip install Flask pip install Flask-RESTful 仅简单请求url,然后出发处理程序,返回处理结果 app.py代码如下 f ...