试试 IEnumerable 的 10 个小例子
IEnumerable 接口是 C# 开发过程中非常重要的接口,对于其特性和用法的了解是十分必要的。本文将通过10个小例子,来熟悉一下其简单的用法。
全是源码
以下便是这10个小例子,响应的说明均标记在注释中。
每个以 TXX 开头命名的均是一个示例。建议从上往下阅读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Xunit; using Xunit.Abstractions; namespace Try_More_On_IEnumerable { public class EnumerableTests { private readonly ITestOutputHelper _testOutputHelper; public EnumerableTests( ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; } [Fact] public void T01普通的循环获取偶数() { // 创建一个集合存放最终结果 var result = new List< int >(); for ( var i = 0; i <= 10; i++) { // 如果是偶数的话,将数字放入集合中 if (i % 2 == 0) { result.Add(i); } } // 断言最终的结果 result.Should().Equal(0, 2, 4, 6, 8, 10); } [Fact] public void T02普通Enumerable() { // 通过静态方法获取偶数的Enumerable对象 var result = GetNumber(10); // 断言结果 result.Should().Equal(0, 2, 4, 6, 8, 10); /** * 这种写法比起 T01 的写法少了一个集合的创建,通常来说是性能更佳的写法 */ } /// <summary> /// 获取小于等于max的偶数 /// </summary> /// <param name="max"></param> /// <returns></returns> private static IEnumerable< int > GetNumber( int max) { for ( var i = 0; i <= max; i++) { if (i % 2 == 0) { // 使用 yield return 返回每次迭代的结果 yield return i; } } } [Fact] public void T02本地函数() { // 通过本地函数获取结果 var result = GetNumber(10); // 断言结果 result.Should().Equal(0, 2, 4, 6, 8, 10); /** * 使用本地函数获取 Enumerable 对象。 * 此处的效果和静态方法类似。 * 本地函数是 C# 7.0 才开始支持的语法特性。 * 关于本地函数详细内容可以参见:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/local-functions */ IEnumerable< int > GetNumber( int max) { for ( var i = 0; i <= max; i++) { if (i % 2 == 0) { yield return i; } } } } [Fact] public void T03分离条件() { /** * 使用 Where 过滤结果 * 这样的做法分离了“自增”逻辑和“判断是偶数”的逻辑 */ var result = GetNumber(10) .Where(x => x % 2 == 0); result.Should().Equal(0, 2, 4, 6, 8, 10); // 迭代时只是进行了自增操作 IEnumerable< int > GetNumber( int max) { for ( var i = 0; i <= max; i++) { yield return i; } } } [Fact] public void T04Linq产生数值() { // 系统内置了一个方法来获取数字的自增序列,因此可以如此简化 var result = Enumerable .Range(0, 11) .Where(x => x % 2 == 0); result.Should().Equal(0, 2, 4, 6, 8, 10); } [Fact] public void T05输出233() { // 输出3个数字 233 var result = Get233().Take(3); result.Should().Equal(2, 3, 3); // 输出5个数字 23333 result = Get233().Take(5); result.Should().Equal(2, 3, 3, 3, 3); IEnumerable< int > Get233() { // 第一次输出 2 yield return 2; while ( true ) { // 后面都输出 3 yield return 3; } } /** * 值得注意的是 while(true) 并不会导致程序陷入死循环 * 因为 yield return 是采用按需供给的方式执行的。 * 关于这点可以参考右侧文章:https://www.cnblogs.com/SilentCode/p/5014068.html */ } [Fact] public void T06获取10个小于50的随机数() { /** * 过滤随机数中小于50的数字,只获取其中10个结果 */ var result = GetRandom() .Where(x => x < 50) .Take(10) .ToArray(); // 断言 result.Should().HaveCount(10); result.All(x => x < 50).Should().BeTrue(); IEnumerable< int > GetRandom() { var random = new Random(); // 不断输出 0-100 的随机数 while ( true ) { yield return random.Next(0, 100); } } } [Fact] public void T07自动补足随机数() { // 获取3个数字 var result1 = GetData().Take(3); // 3 个数字分别为 0,1,2 result1.Should().Equal(0, 1, 2); // 获取 10 个数字 var result2 = GetData().Take(10).ToArray(); // 前 5 个数字分别为 0,1,2,3,4 result2.Take(5).Should().Equal(0, 1, 2, 3, 4); // 从第 5 个开始的数字都大于 10 result2.Skip(5).Take(5).Should().Match(x => x.All(a => a > 10)); /** * 获取一组数据,前5个数字是 0,1,2,3,4 。后面继续获取则为随机数 */ IEnumerable< int > GetData() { var staticData = new [] {0, 1, 2, 3, 4}; foreach ( var i in staticData) { yield return i; } var random = new Random(); // 不断输出 10-100 的随机数 while ( true ) { yield return random.Next(10, 100); } } } [Fact] public void T08条件转循环() { var book1 = GetReadingBook(DateTime.Parse( "2019-08-30" )).First(); book1.Should().Be( "每个周五都是快乐的一天" ); var book2 = GetReadingBook(DateTime.Parse( "2016-02-29" )).First(); book2.Should().Be( "四年一次的邂逅" ); var book3 = GetReadingBook(DateTime.Parse( "2019-09-01" )).First(); book3.Should().BeSameAs( "月老板软件开发小妙招三十二则" ); // 获取给定时间需要阅读的书籍名称 IEnumerable< string > GetReadingBook(DateTime time) { // 周五 if (time.DayOfWeek == DayOfWeek.Friday) { yield return "每个周五都是快乐的一天" ; } // 2月29日 if (time.Date.Month == 2 && time.Date.Day == 29) { yield return "四年一次的邂逅" ; } // 其他时间阅读名著 yield return "月老板软件开发小妙招三十二则" ; } } [Fact] public void T09获取一个链接字符串() { // 获取一个当前可用的链接字符串 var conn = GetConnectionString().FirstOrDefault(); conn.Should().Be( "Source=赛博坦;UID=月x;Password=******" ); IEnumerable< string > GetConnectionString() { // 从一个文件中获取链接字符串 var connFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "conn.txt" ); if (File.Exists(connFilename)) { var fileContent = File.ReadAllText(connFilename); yield return fileContent; } // 从配置文件中读取链接字符串 var dbConnectionString = ConfigurationManager.ConnectionStrings[ "db" ]?.ConnectionString; if (! string .IsNullOrEmpty(dbConnectionString)) { yield return dbConnectionString; } // 返回默认的字符串 yield return "Source=赛博坦;UID=月x;Password=******" ; } } [Fact] public async Task T10测试网络连接() { var httpClient = new HttpClient(); try { await Task.WhenAll(SendRequests()); _testOutputHelper.WriteLine( "当前网络连接正常" ); } catch (Exception e) { _testOutputHelper.WriteLine( "当前网络不正常,请检查网络连接" ); } IEnumerable<Task> SendRequests() { yield return Task.Run(() => httpClient.GetAsync( "http://www.baidu.com" )); yield return Task.Run(() => httpClient.GetAsync( "http://www.bing.com" )); yield return Task.Run(() => httpClient.GetAsync( "http://www.taobao.com" )); } } } } |
源码说明
以上示例的源代码放置于博客示例代码库中。
项目采用 netcore 2.2 作为目标框架,因此需要安装 netcore 2.2 SDK 才能运行。
- 本文作者: Newbe36524
- 本文链接: http://www.newbe.pro/2019/09/01/Others/Try-More-On-IEnumerable/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了