西部一侠 發表於 2019-6-5 17:05:00

C#编程语言及.NET 平台快速入门指南

<div>github:&nbsp;https://github.com/mfjiang</div>
<div>e-mail: hamlet.jiang@live.com</div>
<div>&nbsp;</div>
<div>
<h1>⼀、C#,CLR,IL,JIT概念&nbsp;以及 .NET 家族</h1>
<h2>(⼀)基础概念</h2>
<div>C# (念作 C Sharp) 是在CLR上实现的一种编程语言,也是.NET平台上最通用的编程语言,它在语法上借鉴了Java和C++风格,但更为精简。Borland Turbo Pascal编译器的主要作者安德斯·海尔斯伯格(Anders Hejlsberg)是C#与.NET平台的创始人。本文诣在为初次接触C#和.NET平台的用户提供较全面的路线指引,也为早期.NET开发人员介绍当代.NET平台的新特性。</div>
<div>&nbsp;</div>
<div>相对于 C 和 C++,C# 在许多方面进行了限制和增强:</div>
<div>1、指针(Pointer)只能用于不安全模式之中。大多数对象访问通过安全的引用实现,以避免无效的调用,并且有许多算法用于验证溢出,指针只能用于调用值类型,以及受垃圾收集控制的托管对象。</div>
<div>2、对象不能被显式释放,代替为当不存在被引用时通过垃圾回收器回收。</div>
<div>3、只允许单一继承(single inheritance),但是一个类可以实现多个接口(interfaces)。</div>
<div>4、C# 比 C++ 更加类型安全。默认的安全转换是隐含转换,例如由短整型转换为长整型和从派生类转换为基类。而接口布尔型同整型,及枚举型同整型不允许隐含转换,非空指针(通过引用相似对象)同用户定义类型的隐含转换字段被显式的确定,不同于C++的复制构造函数。</div>
<div>5、数组声明语法不同("int[] a = new int"而不是"int a")。</div>
<div>6、枚举位于其所在的名字空间中。</div>
<div>7、C# 中没有模版(Template),但是在C# 2.0中引入了泛型(Generic programming),并且支持一些 C++ 模版不支持的特性。比如泛型参数中的类型约束。另一方面,表达式不能像C++模版中被用于类型参数。</div>
<div>8、属性支持,使用类似访问成员的方式调用。</div>
<div>9、完整的反射支持。</div>
<div>&nbsp;</div>
<div>&nbsp;CLR-Common Language Runtime 意为公共语⾔运⾏库,它是⼀个可由多种不同编程语⾔使⽤的运⾏库,只要是⾯向 CLR 的编译器编译的编程语⾔都被 CLR ⽀持。</div>
<div>&nbsp;</div>
<div>&nbsp;IL-Intermediate Language,意为中间语⾔,⾯向 CLR 的编程语⾔被编译为IL代码,IL代码也被称为托管代码,它是与 CPU ⽆关的机器语⾔,是⼀种⾯向对象的机器语⾔。每⼀个 IL 代码⽂件被称为托管模块(managed module)。托管模块是 ⼀个32位或是64位可移植执⾏体⽂件,它们需要CLR才能执⾏。</div>
<div>&nbsp;</div>
<div>&nbsp;每个托管模块带有相应的元数据(metadata),元数据描述模块中定义的内容,⽐如类型及成员、导⼊的类型及成员。每 个托管模块由操作系统头信息、CLR头(记录版本、⼊口⽅法等)、元数据、IL代码(CLR在运⾏时将IL编译成本地CPU 指令)。 ⼀个.NET程序集是由⼀个或者多个托管模块和资源⽂件组成,程序集是⼀个或是多个托管模块的逻辑分组,是最⼩的可重用、安全性及版本控制单元。</div>
<div>&nbsp;</div>
<div>&nbsp;JIT-just-in-time,意为CLR对IL代码进⾏即时编译的过程,CLR拥有进⾏JIT过程的编译器(JITComiler),它将要调⽤的 IL 代码编译为本地 CPU 指令。</div>
<div>&nbsp;</div>
<div>.NET CORE&nbsp;即将像C++一样支持 Intel CPU SIMD&nbsp;指令集(从SSE到AVX2),参考下列资料:</div>
<div>https://fiigii.com/2019/03/03/Hardware-intrinsic-in-NET-Core-3-0-Introduction/&nbsp;英文</div>
<div>https://mp.weixin.qq.com/s/ifFOUoUWG3-s9CEcOqWzYQ&nbsp;中文</div>
<div>&nbsp;</div>
<h2>(二).NET 家族</h2>
<div>本文将Windows上的.NET Framework称为经典 .NET,由公共语⾔运⾏库(CLR)和类库(FCL --Framework Class Library)构成。</div>
<div>&nbsp;</div>
<div>.NET Core&nbsp;是&nbsp;经典.NET 的跨平台实现,.NET Standard是 .NET Core&nbsp;和 .NET Framework之间的通用库。</div>
<div>&nbsp;</div>
<div>.NET 5 开始统一了.NET Core、.NET Framework 4.x、Mono等分支形成了一个统一的技术平台。</div>
<div>&nbsp;</div>
<div>.NET 6 是首个原生支持苹果芯片 (Arm64) 的版本,并且还针对 Windows Arm64 进行了改进。C# 10和F# 6提供了语言改进,优化了代码,在性能上有了巨大的提升,使用dotnet monitor和OpenTelemetry改进了云诊断。ASP.NET Core 中引入了最少的 API,提高了 HTTP 服务的性能,.NET 6 开始引入了MAUI技术,提供跨系统平台的UI开发框架。</div>
<div>&nbsp;</div>
<div><img src="https://img2020.cnblogs.com/blog/86685/202112/86685-20211224094229467-1962902252.png" alt="" width="961" height="514" loading="lazy">
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div>Mono是一个由Xamarin公司所主持的开源项目。该项目的目标是创建一系列匹配ECMA标准的.NET工具,包括C#编译器和通用语言架构。</div>
<div>ML.Net&nbsp;是.NET上实现的AI开发框架(自.NET Core 就开始存在)。<br><img src="https://img2020.cnblogs.com/blog/86685/202112/86685-20211224094702565-1171915967.png" alt="" width="1070" height="700" loading="lazy">
<p>&nbsp;</p>
<p>&nbsp;</p>




</div>
<div>&nbsp;</div>
<div>开发Windows应用建议选择经典.NET (v.4.x)或 .NET Core 3.1 (Winfrom和WPF);<br>开发面向Window 10/11的桌面程序时,建议使用.NET 6 和 Windows App SDK + MAUI;</div>
<div>开发Linux上的微服务、Web服务、docker容器服务建议使用.NET Core (v.2.2.x、v.3.0.x、v.5.0.x、v.6.0.x)&nbsp;;</div>
<div>开发跨平台手机应用建议使用.NET Xamarin框架(支持ios,Aandroid)或者 .NET 6之上的MAUI;</div>
<div>&nbsp;</div>
<div>
<div>.NET&nbsp;Core&nbsp;3.0&nbsp;正式公布:新特性详细解读</div>
<div>https://www.infoq.cn/article/1eM2A9mfINflb58qa9gs</div>







</div>
<div><br>.NET 6.0&nbsp;</div>
<div>.NET 生态系统的蜕变之 .NET 6 - 张善友 - 博客园 (cnblogs.com)&nbsp;</div>
<div><br>.NET 6 正式发布,迄今为止最快的.NET</div>
<div>Announcing .NET 6 - The Fastest .NET Yet - .NET Blog (microsoft.com)<br></div>
<div>&nbsp;</div>
<div><span style="background-color: rgba(128, 128, 0, 1)">注:Visual Studio 2019 支持用户使用以上任何一个框架开发应用,并内置相关应用场景的项目模板。</span></div>
<div><span style="background-color: rgba(128, 128, 0, 1)">Visual Studio 2017支持.NET v.4.x&nbsp;及.NET Core 2.2的项目开发。</span></div>
<div>&nbsp;</div>
<div>微软公司在2014年开源了Roslyn编译器,随后成立了.NET 开源基金会,并在 Github上以MIT协议公开了.NET源代码。详情参考: https://github.com/dotnet</div>
<div>&nbsp;</div>
<div><span style="color: rgba(0, 128, 0, 1)">.NET 5 在2020年推出,它将统一目前所有的 .NET 分支,.NET 6 已经于2021年11月8日正式发布。</span></div>
<div><span style="color: rgba(0, 128, 0, 1)"><span style="color: rgba(0, 128, 0, 1)"><img src="https://img2018.cnblogs.com/blog/86685/201906/86685-20190605161350135-571152488.png" alt="" style="border: 1px solid rgba(0, 0, 0, 1)"></span></span></div>
<div>
<p>上图为.NET 5&nbsp;架构图</p>
<p><img src="https://img2018.cnblogs.com/blog/86685/201906/86685-20190605161459162-1941249045.png" alt="" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p>上图是 .NET 发布路线图</p>
<p>&nbsp;</p>
<p><img src="https://img2020.cnblogs.com/blog/86685/202112/86685-20211202105309150-985269580.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>上图是.NET 6的架构</p>
<p>&nbsp;</p>
<p>一家名为iolevel的公司推出了peachpie编译器(https://www.peachpie.io/)致力于将PHP语言带到.NET平台。他们之前是一所大学团体(位于布拉格的查尔斯大学),推出过名为Phalanger的编译器(&nbsp;https://github.com/DEVSENSE/Phalanger)将一部分Facebook的开源代码转换为.NET代码来执行。这些都可以证明.NET平台的先进性。点击这里了解一些peachpie的背景:https://kb.cnblogs.com/page/138573/</p>
<p>&nbsp;</p>
<h2>2022年以及之后发布的重大版本</h2>
<p>以下是&nbsp;<strong>.NET 7、8、9、10</strong>&nbsp;四个主要发行版本的关键特性清单(聚焦运行时、语言、ASP.NET Core、性能、云原生等最重要变化)。这些版本的发布时间和支持类型也一并列出,便于对照。</p>
<table>
<thead>
<tr><th>版本</th><th>发布年月</th><th>支持类型</th><th>支持时长</th><th>关键特性清单(精选 Top 10~12 项最具代表性变化)</th></tr>

</thead>
<tbody>
<tr>
<td><strong>.NET 7</strong></td>
<td>2022年11月</td>
<td>STS</td>
<td>≈18个月</td>
<td>• C# 11 / F# 7 新特性(raw string literals、list patterns 等)<br>• 显著的性能提升(≈20–30% runtime 改进)<br>• Native AOT 大幅增强(尤其是 console / worker)<br>• Rate Limiting Middleware(限流)正式版<br>• Output Caching(输出缓存)<br>• Minimal APIs 增强(过滤器、参数绑定改进)<br>• System.Text.Json 序列化性能提升 + 源生成器改进<br>• Microsoft.Extensions 遥测 / OpenTelemetry 更好支持<br>• .NET MAUI 正式 GA(但仍较不稳定)<br>• Windows Forms / WPF 的一些现代化改进<br>• Arm64 性能优化</td>


</tr>
<tr>
<td><strong>.NET 8</strong></td>
<td>2023年11月</td>
<td><strong>LTS</strong></td>
<td>3年</td>
<td>• C# 12(primary constructors、collection expressions、default lambda params)<br>• Blazor&nbsp;<strong>全栈统一模型</strong>(Server + WebAssembly 混合渲染最成熟)<br>• Native AOT 生产级可用度大幅提升(云 / 容器场景推荐)<br>• Frozen Collections(不可变高性能集合)<br>• 垃圾回收器改进 + 动态PGO更强<br>• ASP.NET Core:身份验证/授权 API 简化、请求大小写不敏感路由<br>• .NET Aspire(云原生开发栈)首次亮相<br>• System.Text.Json 源生成器更完善<br>• .NET MAUI 更稳定 + Hot Reload 改进<br>• 容器镜像构建原生支持(dotnet publish —os linux —arch x64)<br>• 性能整体再提升 ≈15–40%(视场景)</td>


</tr>
<tr>
<td><strong>.NET 9</strong></td>
<td>2024年11月</td>
<td>STS</td>
<td>18个月</td>
<td>• C# 13(params collections、ref struct interfaces、escape analysis、field 关键字)<br>•&nbsp;<strong>DATAS</strong>(Dynamic Adaptation To Application Sizes)成为 Server GC 默认替代<br>• 更多 JIT 优化(循环优化、Arm64 向量化、Inlining 改进)<br>• 新 LINQ 方法:CountBy / AggregateBy / Index<br>• OrderedDictionary&lt;tkey,tvalue&gt;&nbsp;泛型版本<br>• 特性开关(Feature Switches)新属性模型 + trimming 支持<br>• ASP.NET Core:更强的 AOT 支持、OpenTelemetry 增强<br>• HybridCache(新的混合缓存库)<br>• NuGet audit 集成到 dotnet CLI<br>• BuildCheck(构建时检查)<br>• 后量子密码学初步增强<br>• .NET MAUI / EF Core / ML.NET 都有明显进步</td>


</tr>
<tr>
<td><strong>.NET 10</strong></td>
<td>2025年11月</td>
<td><strong>LTS</strong></td>
<td>3年</td>
<td>• C# 14(extension members、field 关键字完善、null-conditional assignment ??=、partial constructors/events 等)<br>• JIT 进一步优化(struct 参数寄存器传递、loop inversion、devirtualization)<br>• AVX10.2 支持 + NativeAOT 大幅增强<br>• 密码学:后量子算法(ML-DSA / HashML-DSA / Composite ML-DSA)更完整支持<br>• System.Text.Json:禁止重复属性、PipeReader 支持、更严格模式<br>• 新增 WebSocketStream、TLS 1.3 macOS 客户端支持<br>• Microsoft Agent Framework(AI Agent 框架)内置支持<br>• dotnet test 支持 Microsoft.Testing.Platform<br>• 容器镜像格式显式控制 + console app 原生产镜像<br>• dotnet tool exec(一次性工具执行)<br>• Visual Studio 2026 + AI 辅助开发体验大幅提升</td>


</tr>


</tbody>


</table>
<h3 id="h3--2026-">快速对比总结(2026年视角)</h3>
<ul>
<ul>
<li><strong>最推荐生产长期使用</strong>:目前(2026年1月)首选&nbsp;<strong>.NET 8 LTS</strong>(仍在支持期内)或尽快迁移到&nbsp;<strong>.NET 10 LTS</strong>(最新长期支持版)</li>
<li><strong>追求最新性能 &amp; 云原生</strong>:优先 .NET 10(或至少 .NET 9)</li>
<li><strong>最显著的转折点</strong>:
<ul>
<li>.NET 7 → Native AOT 开始实用</li>
<li>.NET 8 → Blazor 全栈 + Aspire + Frozen collections</li>
<li>.NET 9 → DATAS 默认 + LINQ新方法 + HybridCache</li>
<li>.NET 10 → 后量子密码学 + AI Agent框架 + C# 14 大幅减少样板代码</li>


</ul>


</li>


</ul>

</ul>
<h1>二、C#&nbsp;语言要点</h1>
<h2>(一)基元类型</h2>
<table align="center"><colgroup><col><col><col></colgroup>
<tbody>
<tr>
<td>C#类型</td>
<td>FCL&nbsp;类型</td>
<td>说明</td>









</tr>
<tr>
<td>Sbyte</td>
<td>System.Sbyte</td>
<td>有符号8位值 (⼀位即1bit,8bit即1byte,下同)</td>









</tr>
<tr>
<td>byte</td>
<td>System.Byte</td>
<td>⽆符号8位值</td>









</tr>
<tr>
<td>Short</td>
<td>System.Int16</td>
<td>有符号16位值</td>









</tr>
<tr>
<td>ushort</td>
<td>System.UInt16</td>
<td>无符号16位值</td>









</tr>
<tr>
<td>int</td>
<td>System.Int32</td>
<td>有符号32位值</td>









</tr>
<tr>
<td>uint</td>
<td>System.UInt32</td>
<td>无符号32位值</td>









</tr>
<tr>
<td>Long</td>
<td>System.Int64</td>
<td>有符号64位值</td>









</tr>
<tr>
<td>ULong</td>
<td>System.UInt64</td>
<td>无符号64位值</td>









</tr>
<tr>
<td>char</td>
<td>System.Char</td>
<td>16位Unicode字符</td>









</tr>
<tr>
<td>Float</td>
<td>System.Single</td>
<td>IEEE32位浮点</td>









</tr>
<tr>
<td>Double</td>
<td>System.Double</td>
<td>IEEE64位浮点</td>









</tr>
<tr>
<td>Bool</td>
<td>System.Boolean</td>
<td>⼀个true/false值</td>









</tr>
<tr>
<td>Decimal</td>
<td>System.Decimal</td>
<td>128位⾼精度浮点值</td>









</tr>
<tr>
<td>String</td>
<td>System.String</td>
<td>⼀个字符数组</td>









</tr>
<tr>
<td>Object</td>
<td>System.Object</td>
<td>所有类型的基类型</td>









</tr>









</tbody>









</table>









</div>
<div>&nbsp;</div>
<div>
<h2><span>(二)引用类型和值类型</span></h2>
<div>CLR⽀持引⽤类型和值类型。 引⽤类型总是从托管堆上分配,C#的new操作符会返回对象的内存地址。结构与枚举都是值类型,与引⽤类型相⽐,值类型是⼀种轻量级的类型,值类型实例是在线程的堆栈上分配,值类型不需要内存指针,不需要垃圾收集处理。所有类型 都是System.Object派⽣,所有值类型都是由System.ValueType抽象类派⽣。</div>
<div>&nbsp;</div>
<div>
<h2>(三) 值类型的装箱与拆箱:</h2>
<div>当需要⼀个值类型进⾏实例引⽤时产⽣装箱(boxing) ,装箱过程是从托管堆中分配内存,并将值类型字段复制到新分 配的堆内存,然后返回新对象的引⽤。&nbsp;</div>
<div>装箱情景:</div>
<div>
<div>
<div class="cnblogs_code">
<pre>Struct Point{<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> int32 x,y;}

Public </span><span style="color: rgba(0, 0, 255, 1)">sealed</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
{
    Public </span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Main()
   {
         ArrayList a </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ArrayList();
         Point p;
         For(int32 i </span>=<span style="color: rgba(128, 0, 128, 1)">0</span>;i&lt;<span style="color: rgba(128, 0, 128, 1)">10</span>;i++<span style="color: rgba(0, 0, 0, 1)">)
         {
             p.x </span>= p.y =<span style="color: rgba(0, 0, 0, 1)"> i;
             a.Add(p);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这⾥产⽣装箱,Add⽅法⼊参必须是Object类型,⽽Object类型是⼀个引⽤类型,值类型P要被装箱为引⽤ 类型。</span>
<span style="color: rgba(0, 0, 0, 1)">         }         
   }
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div>上例中,ArrayList内的p元素是引⽤类型,与原 Point P 结构脱离了关系。</div>
<div>&nbsp;</div>
<div>&nbsp;拆箱情景(unboxing):&nbsp;</div>
<div><span style="color: rgba(0, 0, 255, 1)">Point p2 =(Point)a;//这⾥产⽣拆箱</span></div>
<div>&nbsp;</div>
<div>拆箱是获取已装箱对象各个字段的地址(拆箱关键),并将已经装箱的对象的字段值复制到新的值类型变量的字段。拆 箱时只能将对象拆箱为它装箱时的类型。</div>
<div>&nbsp;</div>
<div>⼿动控制装箱的速度将⽐编译器装箱的速度快。&nbsp;</div>
<div>如:</div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;1)Int32 v =5;Console.writeLine(“{0}{1}{2}”,v,v,v);</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;2)Int32 v=5;object o =v(⼿动装箱);Console.writeLine(“{0}{1}{2}”,o,o,o)//这个⽅法快</span></div>
<h2><span style="font-size: 1.5em">(四)类型、类成员、接口</span></h2>
<div>
<div><strong>类型基础</strong></div>
<div>类型:是可以在类型内部嵌套地定义其他类型的逻辑单位。</div>
<div>类型的成员种类:常量、字段、实例构造器、类型构造器(静态构造)、⽅法、操作符重载、转换操作符、属性、静态 事件、实例事件。</div>
<div>访问修饰符表:</div>
<div>
<table align="center"><colgroup><col><col><col></colgroup>
<tbody>
<tr>
<td>名称</td>
<td>用作类</td>
<td>用作类成员</td>
</tr>
<tr>
<td>
<p>Public</p>
</td>
<td>该类型对所有程序集是可见的</td>
<td>成员可以由所有程序集的所有⽅法访问</td>
</tr>
<tr>
<td>Protected internal</td>
<td>&nbsp;</td>
<td>成员可以由所在类型及其嵌套类型、所有派⽣类型 (不限程序集)、类型所在程序集的所有⽅法访 问。</td>
</tr>
<tr>
<td>Internal</td>
<td>该类型仅在程序集内部可见以及友元程序 集可见</td>
<td>成员可由当前程序集中的所有⽅法访问</td>
</tr>
<tr>
<td>Protected</td>
<td>&nbsp;</td>
<td>成员只能由定义该成员类型中的⽅法、该类型的所 有嵌套类型的⽅法、或者该类型的⼀个派⽣类型 (不限程序集)的⽅法访问</td>
</tr>
<tr>
<td>Private</td>
<td>&nbsp;</td>
<td>成员只能由定义该成员的类型中的⽅法或者该类型 的所有嵌套类型中的⽅法访问</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>组件版本控制修饰符表:</p>
<table align="center"><colgroup><col><col><col><col></colgroup>
<tbody>
<tr>
<td>名称</td>
<td>用作类</td>
<td>用作方法、属性、事件</td>
<td>⽤作常量/字段</td>
</tr>
<tr>
<td>Abstract</td>
<td>表⽰该类型不能构建实例</td>
<td>表⽰在构建派⽣类的实例之前派⽣类 型必须实现这个成员</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Virtual</td>
<td>&nbsp;</td>
<td>表⽰这个成员可以由派⽣类型重写</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Override</td>
<td>&nbsp;</td>
<td>表⽰派⽣类型重写了基类型的成员</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Sealed</td>
<td>表⽰该类型不能⽤作基类</td>
<td>表⽰该成员不能被派⽣类型重写</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>new</td>
<td colspan="2">应⽤于嵌套类型、⽅法、属性、事件、常量或字段时,表⽰该成员与基类中类似的成员没有关系</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<div><strong>静态类(static class):</strong>静态类是不需要实例化,仅拥有静态成员的类型。静态类不⽀持接⼜,这是因为只有使⽤类的实 例的时候才调⽤类的接⼜⽅法。静态类型只包括静态成员,静态类本⾝不能⽤作字段、⽅法参数或者局部变量。</div>
<div>&nbsp;</div>
<div><strong>部分类(partial class):</strong>为了将⼀个类分布在多个⽂件中编辑⽽采⽤partial修饰符,它们在编译后成为⼀个类。</div>
<div>&nbsp;</div>
<div><strong>索引器(indexer):</strong>索引器是⼀种参数化的成员属性。索引器不⽀持静态类型。索引器的作⽤是为类型向外界间接提供 内部的集合成员。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">public object this{get;set;},public object this{get;set;}</span></div>
<div>&nbsp;</div>
<div><strong>可变参数⽅法:</strong>以params关键字修饰的参数称为可变参数,它允许输⼊数量不定的参数来调⽤⽅法。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;Public static double GetAvg(params double[] list){…}; GetAvg(1,2,12,4,3.2);GetAvg(1,57.3);</span></div>
<div>&nbsp;</div>
<div><strong>基类初始化(initializer)调⽤:</strong>⼦类在实例化时可以⼀并调⽤基类的构造函数。这在多个类共享基类构造函数设置的⼀ 些公共成员属性时更便利。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre>Public <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ClassA
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> ClassA(<span style="color: rgba(0, 0, 255, 1)">int</span> a,<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> b){…}
}

Public </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ClassB:ClassA
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> ClassB(<span style="color: rgba(0, 0, 255, 1)">int</span> a,<span style="color: rgba(0, 0, 255, 1)">string</span> b,<span style="color: rgba(0, 0, 255, 1)">bool</span> c):<span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">(a,b){…}
}</span>&nbsp;</pre>
</div>
</div>
<div>&nbsp;</div>
<div>类型的私有构造函数常被⽤于只通过静态⽅法和字段来提供功能的类型。采⽤私有构造函数的类不能被外部类实例化, 但可以在内部实例化。</div>
<div>&nbsp;</div>
<div>&nbsp;静态构造函数⽤于初始化静态成员,也只能访问静态成员,不管类型被实例化多少次,静态构造函数只执⾏⼀次。</div>
<div>&nbsp;</div>
<div><strong>C# 特性标记的使用</strong></div>
<div>
<div class="cnblogs_code">
<pre>
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> CustomerAttribute:Attribute
{
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> String Name{<span style="color: rgba(0, 0, 255, 1)">get</span>;<span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">;}   
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div><strong>使用反射获取特性标记值</strong></div>
<div>
<div class="cnblogs_code">
<pre>
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Sample(){}
Sample o </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Sample();
Type ot </span>= <span style="color: rgba(0, 0, 255, 1)">typeof</span>(o);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">typeof(t)</span>
ot.GetCustomAttributes();</pre>
</div>
</div>
<div>&nbsp;</div>
<div><strong>C# 匿名扩展方法</strong></div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> A
{
      </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> A();
   </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> M1();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> M
{
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> M2(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> A a )
      {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">do sth.</span>
<span style="color: rgba(0, 0, 0, 1)">      }
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<h2>(五) 集合类型 Array\ArrayList\List\HashTable(哈希表)\Dictionary(字典)\Stack(堆栈)\Queue(队列)</h2>
<div><strong>Array类型:</strong>是实现数组的基类,只有系统和编译器可以派⽣。Array提供CreateInstance⽅法进⾏后期绑定,没有公共构 造函数。以下都是声明数组的⽅式:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Array my1DArray=Array.CreateInstance( typeof(Int32), 5 );&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Int32[] my2DArray = new Int32{1,2,3,4,5}</span></div>
<div>&nbsp;</div>
<div><strong>ArrayList类型:</strong>是⼤⼩按需⾃动增加的Array实现,实现了IList接口。以下是ArrayList常见⽤法:</div>
<div><span style="color: rgba(0, 0, 255, 1)">ArrayList myAL = new ArrayList();&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">myAL.Add("Hello");</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">myAL.Add("World"); myAL.Add("!");</span></div>
<div>&nbsp;</div>
<div><strong>HashTable:&nbsp;</strong>表⽰键/值对的集合,这些键/值对根据键的哈希代码进⾏组织。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Main() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Creates and initializes a new Hashtable.</span>
Hashtable myHT = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Hashtable();
myHT.Add(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">First</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
myHT.Add(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Second</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">World</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
myHT.Add(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Third</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Displays the properties and values of the Hashtable.</span>
Console.WriteLine( <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">myHT</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> );
Console.WriteLine( </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Count: {0}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, myHT.Count );
Console.WriteLine( </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Keys and Values:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> );
PrintKeysAndValues( myHT );
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> PrintKeysAndValues( Hashtable myHT ) {
Console.WriteLine( </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\t-KEY-\t-VALUE-</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> );
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> ( DictionaryEntry de <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> myHT )
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\t{0}:\t{1}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, de.Key, de.Value);
Console.WriteLine();
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div><strong>Dictionary:</strong>是HashTable的泛型实现</div>
<div>&nbsp;</div>
<div><strong>Stack:</strong>表⽰对象的简单的后进先出⾮泛型集合。Stack 的容量是 Stack 可以保存的元素数。Stack 的默认初始容量为 10。 向 Stack 添加元素时,将通过重新分配来根据需要⾃动增⼤容量。Stack常被当作循环缓冲区。</div>
<div>&nbsp;</div>
<div><strong>Queue(队列):</strong>是表⽰对象的先进先出集合,与Stack相反。队列在按接收顺序存储消息⽅⾯⾮常有⽤,以便于进⾏顺 序处理。此类将队列作为循环数组实现。存储在 Queue 中的对象在⼀端插⼊,从另⼀端移除。</div>
<div>Queue 的容量是 Queue 可以保存的元素数。Queue 的默认初始容量为 32。向 Queue 添加元素时,将通过重新分配来根据 需要⾃动增⼤容量。</div>
<div>&nbsp;</div>
<h2>(六)泛型</h2>
<div>泛型(generic)是CLR与编程语⾔提供的⼀种实现“算法重⽤”的机制。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;List sl = new List();sl.add(DateTime.Now);sl.add(DateTime.MinValue);</span></div>
<div>&nbsp;</div>
<div>泛型对象设计⽤于管理在类型上成家族的集合,例如设计⼀个⼯⼚类型⽤于创建或修改基于某个接口演变的多个⼦类型 的对象。</div>
<div>&nbsp;</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 为安全成员对象提供公共服务
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">class</span> SecurityMemberService&lt;T&gt; <span style="color: rgba(0, 0, 255, 1)">where</span><span style="color: rgba(0, 0, 0, 1)"> T:ISecurityMember
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> T MemberLogin(<span style="color: rgba(0, 0, 255, 1)">string</span> memberUserName,<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> memberPassword);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> T MemberLogin(<span style="color: rgba(0, 0, 255, 1)">string</span> memberEmail,<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> memberPassword);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> MemberLogout(T member);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span><span style="color: rgba(0, 0, 0, 1)"> T CreateMember(T obj,SecurityMemberInfo info);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> DeleteMember(T member);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> T FindMemberByUserName(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> userName);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> T FindMemberByEmail(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> email);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> LockMember(T member);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> UnlockMember(T member);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> ChangePassword(<span style="color: rgba(0, 0, 255, 1)">string</span> memberName, <span style="color: rgba(0, 0, 255, 1)">string</span> oldPassword,<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> newPassword);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> ChangePasswordQuestionAndAnswer(T member);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">abstract</span> <span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> ResetPasswordAndUpdate(T member);
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>在上例中,SecurityMemberService类型封装了⼀般对ISecurityMember类型的处理⽅法,类型参数T可以是任意 实现了ISecurityMember接⼝的类型,这样对这些类型的⼀般处理并不需要创建额外对应的⼯⼚类型。 注意:泛型类SecurityMemberService有⼀个对类型参数T的约束,它由where关键字指定。</div>
<div>&nbsp;</div>
<div>在⾮泛型类中也可以有泛型⽅法成员,同样泛型⽅法也可有类型约束。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Public class A</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Void M1&lt;T&gt;(T obj){obj.ToString();}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Void M2&lt;T&gt;(T obj)where T:ClassB {obj.ToString();}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div>&nbsp;</div>
<div>委托也可以被设计成泛型,因为委托也可以被当作⽅法的⼀种定义形式,即委托本身描述的是回调⽅法的定义。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Delegate void EventHandler(Object sender,TEventArgs e)where TEventArgs:EventArgs;</span></div>
<div>上例定义的EventHandler要求回调⽅法中的参数e必须是EventArgs类型或是EventArgs的派⽣类型,TEventArgs 是⼀个类型参数,相当于常⻅的T。</div>
<h2><span>(七)线程 (Threading、Lock、Monitor、Mutex)</span></h2>
<div><strong>线程概述:</strong></div>
<div>线程分为前台线程和后台线程,后台线程不妨碍程序的终⽌。线程具有优先级,优先级⾼的线程会得到更多的CPU时 间。多线程可以提⾼对CPU时间的利⽤率,但会占⽤更多的内存等资源。</div>
<div>&nbsp;</div>
<div><strong>线程安全:</strong></div>
<div>Lock关键字可以将⼀段代码定义为互斥段。互斥段在⼀个时刻内只允许⼀个线程进⼊执⾏,⽽其他线程必须等待。如果 有⼀些任务每次只能交给⼀个线程去操作,就可以使⽤Lock关键字将代码定义为互斥段。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Lock(this)&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;&nbsp; &nbsp;&nbsp;//do anything&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div>&nbsp;</div>
<div><strong>Monitor</strong> 类通过向单个线程授予对象锁来控制对对象的访问。对象锁提供限制访问代码块(通常称为临界区)的能⼒。当 ⼀个线程拥有对象的锁时,其他任何线程都不能获取该锁。还可以使⽤ Monitor 来确保不会允许其他任何线程访问正在由 锁的所有者执⾏的应⽤程序代码节,除⾮另⼀个线程正在使⽤其他的锁定对象执⾏该代码。</div>
<div>&nbsp;</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Queue myQueue = new Queue();</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Monitor.Enter(myQueue);</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">//可以在当前线程下对myQueue做任何操作。</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Monitor.Exit(myQueue)//释放锁</span></div>
<div>&nbsp;</div>
<div>为了保证在异常情况下仍可释放锁,Monitor.Exit()⽅法可以放在finally块⾥。调⽤Monitor.Pulse()⽅法会通知预备队列中的 线程可以⽴即使⽤释放的对象。</div>
<div>&nbsp;</div>
<div><strong>Mutex</strong>类是同步基元。当两个或更多线程需要同时访问⼀个共享资源时,系统需要使⽤同步机制来确保⼀次只有⼀个线程 使⽤该资源。</div>
<div>Mutex只向⼀个线程授予对共享资源的独占访问权。如果⼀个线程获取了互斥体,则要获取该互斥体的第⼆个线程将被挂 起,直到第⼀个线程释放该互斥体。已命名的系统互斥体(Mutex)在整个操作系统中都可见,可⽤于同步进程活动。</div>
<div>&nbsp;</div>
<div>与Monitor类不同,Mutex可与WaitHandle⼀起构成“等待机制”,Mutex还可以穿越应⽤程序域。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Test
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Create a new Mutex. The creating thread does not own the
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Mutex.</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Mutex mut = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Mutex();
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">int</span> numIterations = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">int</span> numThreads = <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Main()
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Create the threads that will use the protected resource.</span>
      <span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; numThreads; i++<span style="color: rgba(0, 0, 0, 1)">)
      {
            Thread myThread </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ThreadStart(MyThreadProc));
            myThread.Name </span>= String.Format(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Thread{0}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, i + <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">);
            myThread.Start();
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> The main thread exits, but the application continues to
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> run until all foreground threads have exited.</span>
<span style="color: rgba(0, 0, 0, 1)">    }
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> MyThreadProc()
    {
      </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; numIterations; i++<span style="color: rgba(0, 0, 0, 1)">)
      {
            UseResource();
      }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> This method represents a resource that must be synchronized
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> so that only one thread at a time can enter.</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> UseResource()
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Wait until it is safe to enter.</span>
<span style="color: rgba(0, 0, 0, 1)">      mut.WaitOne();
      Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{0} has entered the protected area</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      Thread.CurrentThread.Name);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Place code to access non-reentrant resources here.
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Simulate some work.</span>
      Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">500</span><span style="color: rgba(0, 0, 0, 1)">);
      Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{0} is leaving the protected area\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      Thread.CurrentThread.Name);

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Release the Mutex.</span>
<span style="color: rgba(0, 0, 0, 1)">      mut.ReleaseMutex();
    }
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<h2>(八) C#&nbsp;面向对象编程、继承、多态、接口、委托、事件</h2>
<div><strong>基本概念</strong></div>
<div>⾯向对象编程(Object –Oriented Programming,OOP),抽象、继承和多态是OOP编程语⾔的三⼤要素。</div>
<div>&nbsp;</div>
<div><strong>继承:</strong>类继承的重要特性是,在希望出现基类型实例的任何地⽅,都可以替换成派⽣类型的实例。类似地,接口继承允许在希望出现已命名接口类型的实例的任何地⽅,都可以替换成实现接口的⼀个类型的实现。</div>
<div>&nbsp;</div>
<div><strong>多态:</strong>指的是多个类型的对象对同⼀消息做出各⾃的处理。多态是⼦类对⽗类的⽅法进⾏重写或替换⽽实现的。&nbsp;</div>
<div>&nbsp;</div>
<div><strong>接口:</strong>接口是⼀组已命名的⽅法签名,在接口内还可以定义事件和属性,它们在本质上也是⽅法。C# 要求接口⽅法标记为 Public。接口的关键价值在于隐藏类型的设计细节,即外部对象不依赖当前对象的内部细节。</div>
<div>&nbsp;</div>
<div><strong>接口特性</strong></div>
<div>接口⽅法的隐式实现:当⽅法签名与继承的接口中的签名⼀致,并且是public或者是viture修饰的⽅法都视为隐式实现了接口⽅法。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Internal sealed class SimpleType:IDisposable</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Public void Dispose(){Console.WriteLine(“Dispose”);}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div>&nbsp;</div>
<div>接口⽅法的显式实现:以接口类型名称作为⽅法前缀时,创建的是⼀个显式接口⽅法实现(explicit interface method implementation,EIMI)。⼀个EIMI⽅法不允许标记访问性(⽐如公共或私有),也不能被标记为virture,因⽽也不能被重 写。显⽰接口⽅法会损害性能,应当谨慎使⽤。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">Internal sealed class SimpleType:IDisposable</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Public void Dispose(){….}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Void IDisposable.Dispose(){….}//显式</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div>&nbsp;</div>
<div>对显式接口的调⽤,需要通过⼀个接口类型的变量来进⾏。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">SimpleType st = new SimpleType();</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">IDisposable d = st;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">d.Dispose();</span></div>
<div>&nbsp;</div>
<div><strong>泛型接口有如下优点:</strong></div>
<div>1、使用接口方法变为强类型。</div>
<div>2、泛型接口在操作值类型时,会减少装箱操作。</div>
<div>3、类可以实现同一个接口若干次,只要使用不同的类型参数。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre>Public <span style="color: rgba(0, 0, 255, 1)">sealed</span> <span style="color: rgba(0, 0, 255, 1)">class</span> Number:IComparable&lt;Int32&gt;,IComparable&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)">
{
Private int32 m_val </span>=<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实现IComparable&lt;Int32&gt;</span>
Public Int32 CompareTo(Int32 n){<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> m_val.CompareTo(n);}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实现IComparable&lt;String&gt;</span>
Public Int32 CompareTo(String s){<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> m_val.CompareTo(Int32.Parse(s));}
}</span>&nbsp;</pre>
</div>
</div>
<div>&nbsp;</div>
<div><strong>委托</strong></div>
<div>委托是.NET中的回调机制。将一个方法绑定到一个委托时,C#和CLR允许引用类型的协变(covariance)和反协变(contra-variance)。协变是指一个方法能返回一个从委托的返回类型派生出来的类型。反协变是指一个方法的参数类型可以是委托的参数类型的基类。但协变对于返回值类型或void的方法不适用。</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">//MyCallback委托</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">Delegate object MyCallback(FileStream s);</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;//SomeMethod⽅法&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">String SomeMethod(Stream s);</span></div>
<div>&nbsp;</div>
<div>上例中,SomeMethod的返回类型(String)继承⾃委托返回类型(Object),这种协变是允许的。SomeMethod的参数类型</div>
<div>(Stream)是委托的参数类型(FileStream)的基类。这种反协变是允许的。</div>
<div>&nbsp;</div>
<div>链式委托指的是⽤⼀个委托回调多个⽅法,即⼀系列委托对象组成的集合。Delegate的公共静态⽅法Combine⽤于添加⼀ 个委托到委托链,Remove⽅法⽤于从链中删除⼀个委托对象。在C#中内置的+=与-=操作符简化了这些操作。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre>Internal <span style="color: rgba(0, 0, 255, 1)">delegate</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Feedback(int32 value);
Feedback fb1 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Feedback(….);
Feedback fb2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Feedback(….);
fbChain </span>=<span style="color: rgba(0, 0, 0, 1)">(Feedback)Delegate.Combine(fbChain,fb1);
fbChain </span>=(Feedback)Delegate.Combine(fbChain,fb2);&nbsp;</pre>
</div>
</div>
<div>⼀组委托是按顺序执⾏的,如果他们带有返回值,只能得到最后⼀个委托的返回值,如果其间有委托⽅法出现致命错误,其它委托就⽆法执⾏。为了克服这些问题,产⽣了MulticastDelegate类,它的GetInvocationList⽅法⽤于显式调⽤链中的每 ⼀个委托,并使⽤符合⾃⼰需求的任何算法。MulticastDelegate类是特殊的类型,只能由系统派⽣,Delegate类已经具备了 MulticastDelegate的能⼒。</div>
<div>&nbsp;</div>
<div><strong>委托的便捷实现:</strong></div>
<div><strong>1. 不构造委托对象</strong></div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">sealed</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> AClass
{
   </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> CallbackWithoutNewingADelegateObject()
    {
      ThreadPool.QueueUserWorkItem(SomeAsyncTask,</span><span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">);
    }
   
   </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> SomeAsyncTask(Object o)
   {
       Console.WriteLine(o);
   }
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div>上例中ThreadPool类的静态⽅法QueueUserWorkItem期望接收⼀个WaitCallback委托对象引⽤,该对象又包含⼀个 SomeAsyncTask⽅法引⽤。因为C#编译器能够⾃⼰进⾏推断,所以我们可以省略构造WaitCallback对象的代码。</div>
<div>&nbsp;</div>
<div><strong>2. 不定义回调⽅法</strong></div>
<div>例:&nbsp;</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">sealed</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> AClass
{
   </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> CallbackWithoutNewingADelegateObject()
   {
      ThreadPool.QueueUserWorkItem(</span><span style="color: rgba(0, 0, 255, 1)">delegate</span>(Object obj){Console.WriteLine(obj);},<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)
   }
} </span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>上例中⽤了⼀段代码块替代了回调⽅法名,编译器会⾃动在类中增加⼀个经过命名的基于此代码块的回调⽅法。</div>
<div>&nbsp;</div>
<div><strong>3. 不指定回调⽅法的参数</strong></div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">button1.Click += delegate(Object sender,EventArgs e){MessageBox.Show(“The Button was clicked”);}&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">//由于上述⽅法中没有⽤到sender与e两个参数,可简写为:</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">button1.Click+=delegate{MessageBox.Show(“ The Button was clicked”);}</span></div>
<div>&nbsp;</div>
<div><strong>4. 不需要将局部变量⼈⼯封装到类中,即可传给⼀个回调⽅法</strong></div>
<div>&nbsp;</div>
<div><strong>事件</strong></div>
<div>事件:在.NET中事件(event)是类的成员,与成员属性和⽅法⼀样。类型的事件,是对外提供的⾃⾝状态的通知。外部类 型通过订阅的形式与事件的发布类型进⾏协作。将事件与处理⽅法关联起来的是委托。.NET中⽤event关键指定特定的委托 来为事件做出响应,这样做可以限制其它⽅法对委托的调⽤(在内部定义委托为私有的,通过event公开,因此外部⽆法访 问委托中的⽅法)。</div>
<div>&nbsp;</div>
<div>设计线程安全的事件,必须显⽰地控制事件的订阅与注销。</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MailManager
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建⼀个作为线程同步锁的私有实例字段</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span> Object m_eventLock = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">增加⼀个引⽤ 委托链表头部的私有字段</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> EventHadler&lt;NewMailEventArgs&gt;<span style="color: rgba(0, 0, 0, 1)"> m_NewMail;

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">增加⼀个事件成员</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">event</span> EventHandler&lt;NewMailEventArgs&gt;<span style="color: rgba(0, 0, 0, 1)"> NewMail
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">显式实现add</span>
<span style="color: rgba(0, 0, 0, 1)">      add
      {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">加私有锁,并向委托链表增加⼀个处理程序以‘value’为参数</span>
      <span style="color: rgba(0, 0, 255, 1)">lock</span>(m_eventLock){m_NewMail+=<span style="color: rgba(0, 0, 0, 1)">value;}
       }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">显式实现remove</span>
<span style="color: rgba(0, 0, 0, 1)">   remove
   {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">加私有锁,并向委托链表移除⼀个处理程序以‘value’为参数 </span>
      <span style="color: rgba(0, 0, 255, 1)">lock</span>(m_eventLock){m_NewMail -=<span style="color: rgba(0, 0, 0, 1)"> value;}
      }
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义⼀个负责引发事件的⽅法,来通知已订阅事件的对象事件已经发⽣,如果类是封装的
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">则需要将⽅法声明为private和non-virtual</span>
    proteted <span style="color: rgba(0, 0, 255, 1)">virtual</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> OnNewMail(NewMailEventArgs e)
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">出于线程安全考虑,将委托字段保存到⼀个临时字段中</span>
      EventHadler&lt;NewMailEventArgs&gt; temp =<span style="color: rgba(0, 0, 0, 1)"> m_NewMail;
      </span><span style="color: rgba(0, 0, 255, 1)">if</span>(temp!=<span style="color: rgba(0, 0, 255, 1)">null</span>){temp(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">,e);}
   }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将输⼊转化为希望的事件</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> SimulateNewMail(String <span style="color: rgba(0, 0, 255, 1)">from</span><span style="color: rgba(0, 0, 0, 1)">,String to,String subject)
   {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构建⼀个对象存放给事件接收者的信息</span>
      NewMailEventArgs e = <span style="color: rgba(0, 0, 255, 1)">new</span> NewMailEventArgs(<span style="color: rgba(0, 0, 255, 1)">from</span><span style="color: rgba(0, 0, 0, 1)">,to,subject);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">引发 </span>
<span style="color: rgba(0, 0, 0, 1)">      OnNewMail(e);
      }
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div><strong>委托与事件</strong></div>
<div>关键字“event”是个修饰词,在绝⼤多数的情形中,被指定为委托(delegate)的对象和被指定为事件(event)的对象是可以互换的。然⽽,事件还有特殊之处:</div>
<div>&nbsp;● 事件就像⼀个委托类型的字段。该字段引⽤了⼀个代表事件处理器的委托,这些处理器是被添加到事件上的;</div>
<div>&nbsp;● 事件只能在声明它的类中被调⽤,⽽所有能见到委托的地⽅都可以使⽤委托;</div>
<div>&nbsp;● 事件可以被包含在接口中⽽委托不可以;</div>
<div>&nbsp;● 事件有可被重写的Add和Remove存取(acccessor)⽅法;</div>
<div>&nbsp;</div>
<div>
<h2>(九)、Linq表达式、异步处理</h2>
<div><strong>LINQ</strong></div>
<div>语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称,比如涵盖:SQL 数据库查询、XML 文档查询、List对象查询、Array对象查询、String对象查询……。&nbsp;借助 LINQ,查询成为了最高级的语言构造,就像类、方法和事件一样。</div>
<div>&nbsp;</div>
<div>示例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> LINQQueryExpressions
{
    </span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Main()
    {
      
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Specify the data source.</span>
      <span style="color: rgba(0, 0, 255, 1)">int</span>[] scores = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">int</span>[] { <span style="color: rgba(128, 0, 128, 1)">97</span>, <span style="color: rgba(128, 0, 128, 1)">92</span>, <span style="color: rgba(128, 0, 128, 1)">81</span>, <span style="color: rgba(128, 0, 128, 1)">60</span><span style="color: rgba(0, 0, 0, 1)"> };

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Define the query expression.</span>
      IEnumerable&lt;<span style="color: rgba(0, 0, 255, 1)">int</span>&gt; scoreQuery =
            <span style="color: rgba(0, 0, 255, 1)">from</span> score <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> scores
            </span><span style="color: rgba(0, 0, 255, 1)">where</span> score &gt; <span style="color: rgba(128, 0, 128, 1)">80</span>
            <span style="color: rgba(0, 0, 255, 1)">select</span><span style="color: rgba(0, 0, 0, 1)"> score;

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Execute the query.</span>
      <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> scoreQuery)
      {
            Console.Write(i </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      }            
    }
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Output: 97 92 81</span></pre>
</div>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div>更详细的Linq用法请参考:</div>
<div>https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/linq/</div>
<div>https://blog.csdn.net/honantic/article/details/46472647</div>
<div>&nbsp;</div>
<div><strong>异步处理</strong></div>
<div>异步是 .NET 中充分使用处理器核心资源的机制,异步机制直接处理多个核心上的阻塞 I/O 和并发操作以提高系统执行效率。</div>
<div>.NET 异步的特点:</div>
<div>1、等待 I/O 请求返回的同时,可通过生成处理更多请求的线程,处理更多的服务器请求。</div>
<div>2、等待 I/O 请求的同时生成 UI 交互线程,并通过将长时间运行的工作转换到其他 CPU 核心,让 UI 的响应速度更快。</div>
<div>&nbsp;</div>
<div>使用基于 .NET 任务的异步模型可直接编写绑定 I/O 和 CPU 的异步代码。 该模型由 Task 和 Task&lt;T&gt; 类型以及 C# 和 Visual Basic 中的 async 和 await 关键字公开。 (有关特定语言的资源,请参见另请参阅部分。)</div>
<div>&nbsp;</div>
<div>Task是用于实现称之为并发 Promise 模型的构造。 简单地说,它们“承诺”,会在稍后完成工作。</div>
<div>Task 表示不返回值的单个操作。</div>
<div>Task&lt;T&gt; 表示返回 T 类型的值的单个操作。</div>
<div>&nbsp;</div>
<div>Task在当前线程上执行,且在适当时会将工作委托给操作系统。 可选择性地通过 Task.Run API 显式请求任务在独立线程上运行。</div>
<div>&nbsp;</div>
<div>示例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义一个基于Task的异步方法</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> Task&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)"> GetHtmlAsync()
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Execution is synchronous here</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> client = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient();
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> client.GetStringAsync(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://www.dotnetfoundation.org</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第二个异步方法</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt; GetFirstCharactersCountAsync(<span style="color: rgba(0, 0, 255, 1)">string</span> url, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> count)
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Execution is synchronous here</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> client = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient();

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Execution of GetFirstCharactersCountAsync() is yielded to the caller here
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> GetStringAsync returns a Task&lt;string&gt;, which is *awaited*</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> page = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> client.GetStringAsync(url);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Execution resumes when the client.GetStringAsync task completes,
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> becoming synchronous again.</span>

    <span style="color: rgba(0, 0, 255, 1)">if</span> (count &gt;<span style="color: rgba(0, 0, 0, 1)"> page.Length)
    {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> page;
    }
    </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
    {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> page.Substring(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, count);
    }
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用示例</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> str = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> GetHtmlAsync();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> str2 = <span style="color: rgba(0, 0, 255, 1)">await</span> GetFirstCharactersCountAsync(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://www.dotnetfoundation.org</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 128, 1)">100</span>);</pre>
</div>
<p>&nbsp;</p>
</div>
<div>&nbsp;</div>
<div>更深入地了解 .NET 上的异步编程</div>
<div>https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index</div>
<div>https://www.cnblogs.com/Cwj-XFH/p/5908562.html</div>
<div>https://www.cnblogs.com/taro/p/7285126.html</div>
<div>&nbsp;</div>
<div><strong>(十、C# 9,10,11 新特性)</strong></div>
<div>1、C# 9 中带来了record 关键字,可以指定类为record类型;<br>
<p>record为引用类型,不用像值类型在传递时需要内存分配,并进行整体拷贝。 重写了Equals(object), IEquatable, 和GetHashCode()这些基本方法,实现值相等,而非引用相等;<br>示例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record Person
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> LastName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> FirstName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> Person(<span style="color: rgba(0, 0, 255, 1)">string</span> first, <span style="color: rgba(0, 0, 255, 1)">string</span> last) =&gt; (FirstName, LastName) =<span style="color: rgba(0, 0, 0, 1)"> (first, last);
}<br></span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> or</span>

<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record Person
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>? FirstName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>? LastName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
}</span></pre>
</div>
<p>为了支持将record对象能解构成元组,我们给record添加解构函数Deconstruct。这种record就称为位置记录。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record Person
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> FirstName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> LastName { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> Person(<span style="color: rgba(0, 0, 255, 1)">string</span> firstName, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> lastName)
      </span>=&gt; (FirstName, LastName) =<span style="color: rgba(0, 0, 0, 1)"> (firstName, lastName);
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Deconstruct(<span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">string</span> firstName, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> lastName)
      </span>=&gt; (firstName, lastName) =<span style="color: rgba(0, 0, 0, 1)"> (FirstName, LastName);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">精简的写法:</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> record Person(<span style="color: rgba(0, 0, 255, 1)">string</span> FirstName, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> LastName);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> person = <span style="color: rgba(0, 0, 255, 1)">new</span> Person(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mads</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Torgersen</span><span style="color: rgba(128, 0, 0, 1)">"</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 位置构造函数</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> (firstName, lastName) = person;               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 位置解构函数

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">一个位置记录可以像下面这样调用父类构造函数</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> record Student(<span style="color: rgba(0, 0, 255, 1)">string</span> FirstName, <span style="color: rgba(0, 0, 255, 1)">string</span> LastName, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> ID) : Person(FirstName, LastName);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用 with 关键字,从前reocrd中取值并修改</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> person = <span style="color: rgba(0, 0, 255, 1)">new</span> Person { FirstName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mads</span><span style="color: rgba(128, 0, 0, 1)">"</span>, LastName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Nielsen</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">var</span> otherPerson = person with { LastName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Torgersen</span><span style="color: rgba(128, 0, 0, 1)">"</span> };<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">改掉了LastName,FirstName仍是 Mads</span></pre>
</div>
<p>record 应用场景:<br>A、web api 中的参数实体类型,它们是一次性传输型数据;<br>B、并发多线程计算中的参数实体类型(并行计算和多线程之间的数据共享);<br>C、大量基于值类型比较和复制的场景;</p>
<p>&nbsp;</p>




</div>
<div>2、C# 10 允许在public struct上创建无参数结构构造函数(不能是partial),也可以通过字段或属性初始化struct的值;<br>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> Address
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Address()
    {
      City </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;unknown&gt;</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> City { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> Address
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> City { <span style="color: rgba(0, 0, 255, 1)">get</span>; init; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;unknown&gt;</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>&nbsp;</p>
</div>
<h1>三、.NET 上的 Web&nbsp;开发: ASP.NET&nbsp;Core</h1>
<div>.NET上的Web解决方案由ASP.NET Core 框架实现,某种程度上你可以将之理解为Java界的Spring MVC。ASP.NET 是经典.NET上的Web解决方案,我们建议新的Web应用应该选择ASP.NET Core。</div>
<div>当前Web开发存在两种主要的风格:MVC,Web API。MVC指的是模型--视图--控制器的Web程序设计模式,而Web API指的是面向RESTful API场景的Web程序设计模式,它仅提供API调用的响应而不关心视图。</div>
<div>&nbsp;</div>
<div><strong>ASP.NET Core</strong></div>
<div>ASP.NET Core MVC 框架由如下基本组件构成:</div>
<div>路由</div>
<div>模型绑定</div>
<div>模型验证</div>
<div>依赖关系注入</div>
<div>筛选器</div>
<div>区域</div>
<div>Web API</div>
<div>Razor 视图引擎</div>
<div>强类型视图</div>
<div>标记帮助程序</div>
<div>视图组件</div>
<div>&nbsp;</div>
<div><strong>控制器:</strong>ASP.NET&nbsp;Core MVC 的Web请求入口是由Controller类型或其子类型的公共方法实现的,一般情况下每个请求入口都是一部分业务逻辑代码的聚合。</div>
<div>&nbsp;</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">public class DefaultController : ControllerBase</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;&nbsp;&nbsp;&nbsp;public ActionResult&lt;string&gt; Index()</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;&nbsp;&nbsp;&nbsp;{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "hello,world";</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div>&nbsp;</div>
<div><strong>路由:</strong>ASP.NET&nbsp;Core MVC&nbsp;建立在 ASP.NET&nbsp;CORE 的路由之上,是一个功能强大的 URL 映射组件,可用于生成具有易于理解和可搜索 URL 的应用程序。 它可让你定义适用于搜索引擎优化 (SEO) 和链接生成的应用程序 URL 命名模式,而不考虑如何组织 Web 服务器上的文件。 可以使用支持路由值约束、默认值和可选值的方便路由模板语法来定义路由。</div>
<div>&nbsp;</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">routes.MapRoute(name: "Default", template: "{controller=Home}/{action=Index}/{id?}");</span></div>
<div>&nbsp;</div>
<div><strong>模型:</strong>ASP.NET&nbsp;Core MVC&nbsp;模型绑定将客户端请求数据(窗体值、路由数据、查询字符串参数、HTTP 头)转换到控制器可以处理的对象中。 因此,控制器逻辑不必找出传入的请求数据;它只需具备作为其操作方法的参数的数据。</div>
<div>&nbsp;</div>
<div>例:</div>
<div><span style="color: rgba(0, 0, 255, 1)">public async Task&lt;IActionResult&gt; Login(LoginViewModel model, string returnUrl = null) { ... }</span></div>
<div>&nbsp;</div>
<div><strong>模型验证:</strong>ASP.NET&nbsp;Core MVC&nbsp;&nbsp;通过使用数据注释验证属性修饰模型对象来支持验证。 验证属性在值发布到服务器前在客户端上进行检查,并在调用控制器操作前在服务器上进行检查。</div>
<div>&nbsp;</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.ComponentModel.DataAnnotations;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> LoginViewModel
{
   
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Email { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }

   
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Password { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }

   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> RememberMe { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}</span></pre>
</div>
</div>
<div>&nbsp;</div>
<div><strong>Razor视图引擎:</strong> Razor&nbsp;是一种紧凑、富有表现力且流畅的模板标记语言,用于使用嵌入式 C# 代码定义视图。 Razor 用于在服务器上动态生成 Web 内容。 可以完全混合服务器代码与客户端内容和代码。我们可以在MVC工程中,往Controller添加请求入口的View文件,这些View文件代表视图文件(.cshtml),这些文件默认使用Razor视图引擎来实现服务端渲染视图。</div>
<div><img src="https://img2018.cnblogs.com/blog/86685/201906/86685-20190605163700208-66479738.png" alt="" style="border: 1px solid rgba(0, 0, 0, 1)">
<div>例:</div>
<div>Index.cshtml:</div>
<div>&nbsp;</div>
<div><span style="color: rgba(0, 0, 255, 1)">&lt;!-- 单行代码块 --&gt;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">@{ var myMessage = "Hello World"; }</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&lt;!-- 行内表达式或变量 --&gt;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&lt;p&gt;The value of myMessage is: @myMessage&lt;/p&gt;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&nbsp;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&lt;!-- 多行代码块 --&gt;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">@{</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">var greeting = "Welcome to our site!";</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">var weekDay = DateTime.Now.DayOfWeek;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">var greetingMessage = greeting + " Today is: " + weekDay;</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">}</span></div>
<div><span style="color: rgba(0, 0, 255, 1)">&lt;p&gt;The greeting is: @greetingMessage&lt;/p&gt;</span></div>
<div>&nbsp;</div>
<div>更深入的 Razor 介绍&nbsp; http://www.w3school.com.cn/aspnet/razor_intro.asp</div>
<div>&nbsp;</div>
<div><strong>Web API:&nbsp;</strong>&nbsp;ASP.NET&nbsp;Core&nbsp;支持使用 C# 创建 RESTful 服务,也称为 Web API。 Web API 使用控制器响应这些请求,Web API 中的控制器是派生自 ControllerBase 的类。</div>
<div>&nbsp;</div>
<div>例:</div>
<div>
<div class="cnblogs_code">
<pre></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)]

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ValuesController : ControllerBase
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> ActionResult&lt;Pet&gt;<span style="color: rgba(0, 0, 0, 1)"> Create(Pet pet)
    {
      pet.Id </span>= _petsInMemoryStore.Any() ? _petsInMemoryStore.Max(p =&gt; p.Id) + <span style="color: rgba(128, 0, 128, 1)">1</span> : <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
      _petsInMemoryStore.Add(pet);

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> CreatedAtAction(nameof(GetById),
      </span><span style="color: rgba(0, 0, 255, 1)">new</span> { id =<span style="color: rgba(0, 0, 0, 1)"> pet.Id }, pet);
    }
}</span></pre>
</div>
</div>
<div>&nbsp;</div>
<div><strong>SignalR:</strong> ASP.NET&nbsp;Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。</div>
<div>SignalR 的适用对象:需要来自服务器的高频率更新的应用。</div>
<div>&nbsp;</div>
<div>例如:</div>
<div>游戏、社交网络、投票、拍卖、地图和 GPS 应用;</div>
<div>仪表板和监视应用;</div>
<div>协作应用,例如白板应用和团队会议软件;</div>
<div>需要通知的应用, 社交网络、电子邮件、聊天、游戏、行程警示以及许多其他应用都使用通知;</div>
<div>&nbsp;</div>
<div>SignalR 提供了一个用于创建服务器到客户端远程过程调用(RPC)的 API。 RPC 通过服务器端 .NET Core 代码调用客户端上的 JavaScript 函数。</div>
<div>以下是&nbsp;ASP.NET Core SignalR 的一些功能:</div>
<div>1、自动管理连接。</div>
<div>2、向所有连接的客户端广播消息。 例如,聊天室。</div>
<div>3、将消息发送到特定的客户端或客户端组。</div>
<div>4、扩展以处理增加的流量。</div>
<div>&nbsp;</div>
<div>更深入的了解.NET上的Web开发: https://docs.microsoft.com/zh-cn/aspnet/core/?view=aspnetcore-2.2</div>
</div>
<h1>&nbsp;四、.NET 上的ORM</h1>
<div>
<div><strong>EF6 &amp; EF Core</strong></div>
<div>EntityFramework 6.x (EF6) 是经典 .NET上的 ORM 框架,它功能全面在Windows上运行稳定。</div>
<div>EntityFramework Core (EF Core) 是&nbsp;EntityFramework 的跨平台移植版本,目前功能上与 EF6 仍有差距,可以满足绝大部分 CRUD 操作。</div>
<div>下图是 EF6 与 EF Core 在数据库支持上的对比:&nbsp;</div>
<div><img src="https://img2018.cnblogs.com/blog/86685/201906/86685-20190605163951127-1276605498.png" alt="" style="border: 1px solid rgba(0, 0, 0, 1)">
<div>&nbsp;</div>
<div><strong>其它ORM</strong></div>
<div>dapper&nbsp;是Stack Overflow贡献的轻量级 ORM 框架,兼容.NET Core&nbsp;和 .NET 4.5x,它直接扩展了.NET Connection 对象。</div>
<div>SmartSql&nbsp;是一个包括ORM及延伸功能的数据、缓存读写与配置框架。</div>
<div>&nbsp;</div>
<div>以上介绍的主要的ORM工具都可以在Github上找到其官方主页。</div>
<div>&nbsp;</div>
<h1>五、.NET&nbsp;微服务和容器化</h1>
<div>.NET Core&nbsp; 是最早响应微服务与容器化部署的技术平台。.NET 团队在Docker Hub 官网上维护着所有主要的 .NET Core&nbsp;版本的&nbsp;Docker&nbsp;镜像。</div>
<div>你可以在这个链接上找到这些镜像: https://hub.docker.com/_/microsoft-dotnet-core</div>
<div>&nbsp;</div>
<div>值得一提的是,.NET&nbsp; 在 Docker 上的性能表现超过了大部分其他同类技术平台。例如使用 Raygun&nbsp;工具测试相同 Linux 环境的上运行的 Node.js 与 .NET Core 的性能对比,.NET Core&nbsp;的性能是 Node.js 的2000%。</div>
<div>&nbsp;</div>
<div>.NET Core /.NET 5/.NET 6/&nbsp;&nbsp;是天生为云计算优化的技术平台,有着优良的可伸缩性,并兼容主流的云计算平台,比如 Azure、AWS、阿里云。</div>
<div>&nbsp;</div>
<div><img src="https://img2018.cnblogs.com/blog/86685/201906/86685-20190606160618551-1564702261.png" alt="" style="border: 1px solid rgba(0, 0, 0, 1)">
<p>上图是 .NET Core&nbsp;上实现的微服务与 docker&nbsp;容器部署的典型架构示例</p>
&nbsp;</div>
<div>关于如何设计、发布 .NET Core 的微服务到 Docker 镜像,可以下载这个官方中文说明书: https://dotnet.microsoft.com/download/thank-you/microservices-architecture-ebook-zh-cn</div>
<h1>六、.NET平台与Java平台的互换性</h1>
<table style="height: 934px; width: 1047px" align="center"><colgroup><col><col><col></colgroup>
<tbody>
<tr>
<td>&nbsp;</td>
<td>.NET</td>
<td>Java    </td>
</tr>
<tr>
<td>
<p>包管理</p>
</td>
<td>nuget</td>
<td>Maven</td>
</tr>
<tr>
<td>Web场景开发</td>
<td>
<div>ASP.NET</div>
<div>ASP.NET Core</div>
</td>
<td>Spring Boot</td>
</tr>
<tr>
<td>ORM</td>
<td>
<div>EntityFramework 6.x/7.x/8.x/9.x/10.x</div>
<div>EntityFramework Core</div>
<div>dapper</div>
<div>NHibernate</div>
<div>SmartSql</div>
</td>
<td>
<div>Hibernate</div>
<div>Mybatis</div>
<div>&nbsp;</div>
</td>
</tr>
<tr>
<td>单元测试</td>
<td>
<div>MSUnit</div>
<div>XUnit.net</div>
</td>
<td>JUnit</td>
</tr>
<tr>
<td>Android/ios 开发</td>
<td>Xamarin<br>.NET6/7/8/9/10 MAUI</td>
<td>
<div>Android SDK</div>
<div>RoboVM</div>









</td>









</tr>
<tr>
<td>Windows 开发</td>
<td>
<div>.NET Framework 4.x</div>
<div>.NET Core 3.1+<br>.NET 5<br>.NET 6<br>.NET 7/8/9/10</div>









Mono<br>WPF<br>MAUI</td>
<td>
<div>Oracle JDK</div>
<div>Open JDK (free)</div>









</td>









</tr>
<tr>
<td>Mac OS 开发</td>
<td>
<div>Mono</div>
<div>Xamarin/.NET Core</div>









</td>
<td>
<div>Oracle JDK</div>
<div>Open JDK(free)</div>









</td>









</tr>
<tr>
<td>linux开发</td>
<td>
<div>Mono</div>
<div>.NET Core 3.1<br>.NET 5<br>.NET 6<br>.NET 7/8/9/10</div>









</td>
<td>
<div>Oracle JDK</div>
<div>Open JDK(free)</div>









</td>









</tr>
<tr>
<td>docker支持</td>
<td>
<div>.NET Core 2.1/3.1<br>.NET 5<br>.NET 6<br>.NET 7/8/9/10</div>
<div>Mono</div>









</td>
<td>
<div>Oracle JDK</div>
<div>Open JDK(free)</div>









</td>









</tr>
<tr>
<td>AI/数据分析</td>
<td>
<div>ML.net<br>
ONNX Runtime<br>
Microsoft Cognitive Toolkit(CNTK)</div>
<div>tensorflow.net</div>
<div>.NET for Apache Spark</div>



































</td>
<td>
<div>Eclipse Deeplearning4j</div>
<div>Apache OpenNLP</div>
<div>Java-ML</div>
<div>Spark</div>
<div>Flink</div>
<div>Kafka</div>
<div>Storm</div>



































</td>



































</tr>
<tr>
<td>游戏开发</td>
<td>
<div>Unity (C#语言)</div>
<div>MonoGame</div>
<div>CRYENGINE</div>



































</td>
<td>&nbsp;</td>



































</tr>
<tr>
<td>IoT</td>
<td>System.Device.Gpio (nuget)<br>Iot.Device.Bindings(nuget)</td>
<td>Open IoT Stack for Java</td>



































</tr>
<tr>
<td>即时通信</td>
<td>SignalR</td>
<td>&nbsp;</td>









</tr>



































</tbody>


































</table>
































<br>

</div>
<p>&nbsp;</p>
<div>以上关于 .NET 平台及 Java 平台的比较信息来源于一小部分有代表性的技术栈,仅供参考。</div>
<div>关于 .NET 平台更多的生态内容可以参考这个链接:https://github.com/thangchung/awesome-dotnet-core</div>
<div>&nbsp;</div>
<div>感谢 .NET 社群中的朋友帮忙审校。</div>
<div>&nbsp;</div>
<div>参考链接:</div>
<div>https://dotnet.microsoft.com<br>https://docs.microsoft.com/zh-cn/aspnet/core/?view=aspnetcore-2.2<br>https://dotnet.microsoft.com/learn/web/microservices-architecture</div>
<div>https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/linq/</div>
<div>https://devblogs.microsoft.com/dotnet/</div>
<div>https://hub.docker.com/_/microsoft-dotnet-core</div>
<div>http://www.w3school.com.cn/aspnet/razor_intro.asp</div>
<div>https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index</div>
<div>https://www.cnblogs.com/Cwj-XFH/p/5908562.html</div>
<div>https://www.cnblogs.com/taro/p/7285126.html</div>
<div>https://blog.csdn.net/honantic/article/details/46472647<br>https://kb.cnblogs.com/page/138573/<br></div>
<div>
<div>https://fiigii.com/2019/03/03/Hardware-intrinsic-in-NET-Core-3-0-Introduction/&nbsp;</div>
<div>https://mp.weixin.qq.com/s/ifFOUoUWG3-s9CEcOqWzYQ&nbsp;</div>
<div>https://www.infoq.cn/article/1eM2A9mfINflb58qa9gs</div>











</div>






























</div>


































</div>


































</div>


































</div>


































</div>


































</div>


































</div>


































</div>
<p>&nbsp;</p>
<h1 style="margin: 8px 0 25px; padding: 0; font-size: 40px; line-height: 1.5; color: rgba(51, 51, 51, 1); font-family: &quot;Microsoft Yahei&quot;, Avenir, &quot;Segoe UI&quot;, &quot;Hiragino Sans GB&quot;, STHeiti, &quot;Microsoft Sans Serif&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif">迄今为止最快</h1><br><br>
来源:https://www.cnblogs.com/JiangMingFeng/p/10980549.html
頁: [1]
查看完整版本: C#编程语言及.NET 平台快速入门指南