通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?


什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的概念,先从类型系统开始讲起,我将通过跨语言操作这个例子来逐渐引入一系列.NET的相关概念,这主要包括:CLS、CTS(CLI)、FCL、Windows下CLR的相关核心组成、Windows下托管程序运行概念、什么是.NET Framework,.NET Core,.NET Standard及一些VS编译器相关杂项和相关阅读链接。完整的从上读到下则你可以理解个大概的.NET体系。

文章是我一字一字亲手码出来的,每天下班用休息时间写一点,持续了二十来天。且对于文章上下衔接、概念引入花了很多心思,致力让很多概念在本文中显得通俗。但毕竟.NET系统很庞大,本文篇幅有限,所以在部分小节中我会给出延伸阅读的链接,在文章结尾我给出了一些小的建议,希望能对需要帮助的人带来帮助,如果想与我交流可以文章留言或者加.NET技术交流群:166843154

目录

  • .NET和C#是什么关系
  • 跨语言和跨平台是什么
  • 什么是跨语言互操作,什么是CLS
    • CLS异常
  • 什么是CTS?
  • 什么是类库?
    • 什么是基础类库BCL?
    • 什么是框架类库FCL?
  • 什么是基元类型?
  • System.Object的意义
  • 计算机是如何运行程序的?
    • 什么是CPU?
    • 什么是高级编程语言?
  • 什么是托管代码,托管语言,托管模块?
    • 非托管的异常
  • 什么是CLR,.NET虚拟机?
  • 什么是CLR宿主进程,运行时主机?
  • Windows系统自带.NET Framework
  • .NET Framework 4.0.30319
    • .NET Framework4.X覆盖更新
    • 如何确认本机安装了哪些.NET Framework和对应CLR的版本?
  • 什么是程序集
  • 用csc.exe进行编译
  • .NET程序执行原理
    • JIT编译
    • AOT编译
  • 程序集的规则
    • 程序集的加载方式
    • 强名称程序集
    • 程序集搜索规则
    • 项目的依赖顺序
    • 为什么Newtonsoft.Json版本不一致?
    • 如何在编译时加载两个相同的程序集
    • 如何同时调用两个两个相同命名空间和类型的程序集?
    • 共享程序集GAC
    • 延伸
  • 应用程序域
    • 跨边界访问
    • AppDomain和AppPool
  • 内存
    • 堆栈和堆的区别
    • 线程堆栈
    • 为什么值类型存储在栈上
    • 托管堆模型
    • 选class还是struct
    • GC管理器
    • 弱引用、弱事件
    • GC堆回收
    • 垃圾回收对性能的影响
    • 性能建议
  • .NET程序执行图
  • .NET的安全性
    • 基于角色的安全性
    • 代码访问安全性
  • 什么是.NET
    • 什么是.NET Framework
      • 如何在VS中调试.NET Framework源代码
    • 什么是.NET Core
    • 什么是.NET Standard
    • .NET官方开源项目链接
  • Visual Studio
    • sln解决方案
    • 项目模板
    • csproj工程文件
    • 项目属性杂项
    • IntelliTrace智能追溯
    • 链接
  • 建议

https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.runtimewrappedexception?view=netframework-4.7.2

那么,这个段落总结一下,什么是CLS呢?

在面向.NET开发中,编写跨语言组件时所遵循的那些共性,那些规范就叫做 Common Langrage Specification简称 CLS,公共语言规范
官方CLS介绍:https://docs.microsoft.com/zh-cn/dotnet/standard/language-independence-and-language-independent-components

https://docs.microsoft.com/zh-cn/dotnet/standard/common-type-system

微软已经将CTS和.NET的一些其它组件,提交给ECMA以成为公开的标准,最后形成的标准称为CLI(Common Language Infrastructure)公共语言基础结构。
所以有的时候你见到的书籍或文章有的只提起CTS,有的只提起CLI,请不要奇怪,你可以宽泛的把他们理解成一个意思,CLI是微软将CTS等内容提交给国际组织计算机制造联合会ECMA的一个工业标准。

https://msdn.microsoft.com/zh-cn/library/azure/system.runtime.exceptionservices.handleprocesscorruptedstateexceptionsattribute.aspx
SEHException类:https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.sehexception(v=vs.100).aspx
处理损坏状态异常博客专栏: https://msdn.microsoft.com/zh-cn/magazine/dd419661.aspx

https://msdn.microsoft.com/zh-cn/library/9x0wh2z3(v=vs.85).aspx
CLR集成: https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/ms131052(v%3dsql.100)
构造CLR的接口:https://msdn.microsoft.com/zh-cn/library/ms231039(v=vs.85).aspx
适用于 .NET Framework 2.0 的宿主接口:https://msdn.microsoft.com/zh-cn/library/ms164336(v=vs.85).aspx
选择CLR版本: https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/startup/supportedruntime-element

所以C#编写的程序如果想运行就必须要依靠.NET提供的CLR环境来支持。 而CLR是.NET技术框架中的一部分,故只要在Windows系统中安装.NET Framework即可。

https://baike.baidu.com/item/Microsoft%20.NET%20Framework/9926417?fr=aladdin

https://docs.microsoft.com/en-us/dotnet/framework/install/guide-for-developers

https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed 。
不过如果不想那么复杂的话,还有种最直接简单的:
那就是进入该目录文件夹,随便找到几个文件对其右键,然后点击详细信息即可查看到对应的文件版本,可以依据文件版本估摸出.NET Framework版本,比如csc.exe文件。

https://stackoverflow.com/questions/402582/mscorlib-dll-system-dll

因为我用了这些类,那么按照编程规则我必须在代码中using这些类的命名空间,并通过csc.exe中的 /r:dll路径 命令来为生成的程序集注册元数据表(即以AssemblyRef为代表的程序集引用表)。
而这些代码引用了4个命名空间,但实际上它们只被包含在mscorlib.dll和System.dll中,那么我只需要在编译的时候注册这两个dll的信息就行了。

好,接下来我将通过cmd运行csc.exe编译器,再输入编译命令: csc /out:D:\demo.exe D:\dic\demo.cs /r:D:\dic\System.dll

/r:是将引用dll中的类型数据注册到程序集中的元数据表中 。
/out:是输出文件的意思,如果没有该命令则默认输出{name}.exe。
使用csc.exe编译生成: https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/compiler-options/command-line-building-with-csc-exe
csc编译命令行介绍:

总之,你除了要掌握基本的编译指令外,当你打上这行命令并按回车后,必须满足几个条件,1.是.cs后缀的c#格式文件,2.是 代码语法等检测分析必须正确,3.是 使用的类库必须有出处(引用的dll),当然 因为我是编译为控制台程序,所以还必须得有个静态Main方法入口,以上缺一不可。

可以看出,这段命令我是将 位于D:\dic\的demo.cs文件给编译成 位于D:\名为demo.exe的控制台文件,并且因为在代码中使用到了System.dll,所以还需要通过/r注册该元数据表。
这里得注意为什么没有/r:mscorlib.dll,因为mscorlib.dll地位的特殊,所以csc总是对每个程序集进行mscorlib.dll的注册(自包含引用该dll),因此我们可以不用/r:mscorlib.dll这个引用命令,但为了演示效果我还是决定通过/nostdlib命令来禁止csc默认导入mscorlib.dll文件。

所以,最终命令是这样的: csc D:\dic\demo.cs /r:D:\dic\mscorlib.dll /r:D:\dic\System.dll /nostdlib

因为没有指定输出文件/out选项, 所以会默认输出在与csc同一目录下名为demo.exe的文件。事实上,在csc的命令中,如果你没有指定路径,那么就默认采用在csc.exe的所在目录的相对路径。

而我们可以看到,在该目录下有许多程序集,其中就包含我们需要的System.dll和mscorlib.dll,所以我们完全可以直接/r:mscorlib.dll /r:System.dll

而类似于System.dll、System.Data.dll这样使用非常频繁的程序集,我们其实不用每次编译的时候都去手动/r一下,对于需要重复劳动的编译指令,我们可以将其放在后缀为.rsp的指令文件中,然后在编译时直接调用文件即可执行里面的命令 @ {name}.rsp。

csc.exe默认包含csc.rsp文件,我们可以用/noconfig来禁止默认包含,而csc.rsp里面已经写好了我们会经常用到的指令。
所以,最终我可以这样写 csc D:\dic\demo.cs 直接生成控制台应用程序。

https://docs.microsoft.com/zh-cn/dotnet/framework/net-native/
Ngen.exe:https://docs.microsoft.com/zh-cn/dotnet/framework/tools/ngen-exe-native-image-generator
Ngen与.NET Native比较:https://www.zhihu.com/question/27997478/answer/38978762

---------------------------------------------------

现在,我们可以通过ILDASM工具(一款查看程序集IL代码的软件,在Microsoft SDKs目录中的子目录中)来查看该程序集的元数据表和Main方法中间码。

c#源码第一行代码:string rootDirectory = Environment.CurrentDirectory;被翻译成IL代码: call string [mscorlib/*23000001*/]System.Environment/*01000004*/::get_CurrentDirectory() /* 0A000003 */ 

这句话意思是调用 System.Environment类的get_CurrentDirectory()方法(属性会被编译为一个私有字段+对应get/set方法)。

点击视图=>元信息=>显示,即可查看该程序集的元数据。
我们可以看到System.Environment标记值为01000004,在TypeRef类型引用表中找到该项:

注意图,TypeRefName下面有该类型中被引用的成员,其标记值为0A000003,也就是get_CurrentDirectory了。
而从其ResolutionScope指向位于0x23000001而得之,该类型存在于mscorlib程序集。

于是我们打开mscorlib.dll的元数据清单,可以在类型定义表(TypeDef)找到System.Environment,可以从元数据得知该类型的一些标志(Flags,常见的public、sealed、class、abstract),也得知继承(Extends)于System.Object。在该类型定义下还有类型的相关信息,我们可以在其中找到get_CurrentDirectory方法。 我们可以得到该方法的相关信息,这其中表明了该方法位于0x0002b784这个相对虚地址(RVA),接着JIT在新地址处理CIL,周而复始。

元数据在运行时的作用: https://docs.microsoft.com/zh-cn/dotnet/standard/metadata-and-self-describing-components#run-time-use-of-metadata

https://docs.microsoft.com/zh-cn/dotnet/framework/app-domains/enhanced-strong-naming

https://docs.microsoft.com/zh-cn/dotnet/framework/app-domains/how-to-disable-the-strong-name-bypass-feature),如果强名称程序集被篡改则报错。

而弱名称程序集则直接按照与程序集名称相等的文件名称来找,如果还是没有找到就以该程序集名称为目录的文件夹下去找。总之,如果最终结果就是没找到那就会报System.IO.FileNotFoundException异常,即尝试访问磁盘上不存在的文件失败时引发的异常。

注意:此处文件名称和程序集名称是两个概念,不要模棱两可,文件CLR头内嵌程序集名称。

举个例子:
我有一个控制台程序,其路径为D:\Demo\Debug\demo.exe,通过该程序的元数据得知,其引用了一个程序集名称为aa的普通程序集,引用了一个名为bb的强名称程序集,该bb.dll的强名称标识为:xx001。
现在CLR开始搜索程序集aa,首先它会从demo.exe控制台的同一目录(也就是D:\Demo\Debug\)中查找程序集aa,搜索文件名为aa.dll的文件,如果没找到就在该目录下以程序集名称为目录的目录中查找,也就是会查 D:\Demo\Debug\aa\aa.dll,这也找不到那就报错。
然后CLR开始搜索程序集bb,CLR从demo.exe的元数据中发现bb是强名称程序集,其标识为:xx001。于是CLR会先从一个被定义为GAC的目录中去通过标识找,没找到的话剩下的寻找步骤就和寻找aa一样完全一致了。

当然,你也可以通过配置文件config中(配置文件存在于应用程序的同一目录中)人为增加程序集搜索规则:
1.在运行时runtime节点中,添加privatePath属性来添加搜索目录,不过只能填写相对路径: 


            "urn:schemas-microsoft-com:asm.v1">
                "relative1;relative2;" /> //程序集当前目录下的相对路径目录,用;号分割
            

2.如果程序集是强签名后的,那么可以通过codeBase来指定网络路径或本地绝对路径。


            "urn:schemas-microsoft-com:asm.v1">
                
                    "myAssembly"
                                      publicKeyToken="32ab4ba45e0a69a1"
                                      culture="neutral" />
                    "2.0.0.0"
                              href="http://www.litwareinc.com/myAssembly.dll" />
                
            

当然,我们还可以在代码中通过AppDomain类中的几个成员来改变搜索规则,如AssemblyResolve事件、AppDomainSetup类等。

有关运行时节点的描述:https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/runtime/runtime-element

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/extern-alias

https://docs.microsoft.com/zh-cn/dotnet/framework/tools/developer-command-prompt-for-vs中)来注册至GAC中,值得一提的是在将强名称程序集安装在GAC中,会效验签名。

GAC工具: https://docs.microsoft.com/en-us/dotnet/framework/tools/gacutil-exe-gac-tool

https://docs.microsoft.com/zh-cn/dotnet/framework/app-domains/application-domains

https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/runtime/gcconcurrent-element
gcServer: https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/runtime/gcserver-element

https://msdn.microsoft.com/zh-cn/library/ms973838.aspx 、 https://msdn.microsoft.com/library/ms973839.aspx

https://docs.microsoft.com/zh-cn/dotnet/standard/security/principal-and-identity-objects#principal-objects

https://msdn.microsoft.com/en-us/library/h846e9b3(v=vs.100).aspx

为了确定代码是否有权访问某一资源或执行某一操作,CLR的安全系统将审核调用堆栈,以将每个调用方获得的权限与要求的权限进行比较。 如果调用堆栈中的任何调用方不具备要求的权限,则会引发安全性异常并拒绝访问。

图出自 https://docs.microsoft.com/zh-cn/dotnet/framework/misc/code-access-security

而除了Permissions权限,代码访问安全性机制还有 权限集、证据、代码组、策略等概念。这些概念让CAS如此强大,但相应的,它们也让CAS变得复杂,必须为每个特定机器定义正确的PermissionSet和Code Groups才能设置成一个成功的CAS策略。

考虑到这层原因,Microsoft .NET安全小组决定从头开始重建代码访问安全性。在.NET Framework4.0之后,就不再使用之前的那套CAS模型了,而是使用.NET Framework 2.0中引入的安全透明模型,然后稍加修改,修改后的安全透明模型成为保护资源的标准方法,被称之为:安全透明度级别2

安全透明度2介绍:https://msdn.microsoft.com/en-us/library/dd233102(v=vs.100).aspx
.NET Framework4.0的安全更改:https://msdn.microsoft.com/en-us/library/dd233103(v=vs.100).aspx
一个完整的CAS演示:https://www.codeproject.com/Articles/5724/Understanding-NET-Code-Access-Security

对于安全透明度级别2我将不再介绍,感兴趣的可以看我推荐的这2篇文章,对Level2的安全透明度介绍的比较详细,包括实践、迁移。
https://www.red-gate.com/simple-talk/dotnet/.net-framework/whats-new-in-code-access-security-in-.net-framework-4.0---part-i/
https://www.red-gate.com/simple-talk/dotnet/net-framework/whats-new-in-code-access-security-in-net-framework-4-0-part-2/

----------------------------------------------

须注意:
.NET平台上的安全机制,仅仅是.NET平台上的,因此它只限制于托管代码,我们可以直接调用非托管代码或进程通信间接调用非托管代码等多个手段来突破对托管代码 操作资源的限制。

事实上,我们在平常项目中代码编写的安全机制(业务逻辑身份验证、项目框架验证)与这些平台级的安全机制没什么不同。我们可以理解为代码写的位置不一样,.NET安全机制是写在CLR组件中,而我们的安全机制是写在上层的代码中。这些平台级的标识更多的是和操作系统用户有关,而我们项目代码中的标识则是和在数据库中注册的用户有关, 大家都是通过if else来去判断,判断的主体和格局不一样,逻辑本质都是相同的。

NET Core不支持代码访问安全性和安全性透明性。

https://docs.microsoft.com/zh-cn/dotnet/framework/deployment/deployment-guide-for-developers
.NET Framework高级开发:https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/29eafad8(v%3dvs.90)
.NET Framework源码在线浏览:https://referencesource.microsoft.com/

https://referencesource.microsoft.com/网站 点击右上角下载源代码。当你调试代码的时候,会提示你无可用源,这个时候你再将你下载下来的源码文件给浏览查找一下就可以了。

如何配置VS来调试.NET Framework源码: https://referencesource.microsoft.com/#q=web 、 https://technet.microsoft.com/zh-cn/cc667410.aspx

还一种方法是,下载.NET Reflector插件,该插件可以帮助我们在VS中直接调试dll,这种方式操作非常简单,不过该插件收费,具体的可以查看我之前写过的文章(群里有该插件的注册版)

https://docs.microsoft.com/en-us/dotnet/core/
.NET基金会:https://dotnetfoundation.org
.NET Core跨平台的行为变更:https://github.com/dotnet/corefx/wiki/ApiCompat
微软宣布.NET开发环境将开源 :https://news.cnblogs.com/n/508410/

https://docs.microsoft.com/zh-cn/dotnet/standard/net-standard#net-implementation-support

.NET Standard开源代码:https://github.com/dotnet/standard

https://github.com/Microsoft/dotnet

  • .NET Core:https://github.com/dotnet/core
  • .NET Core文档:https://github.com/dotnet/docs
  • ASP.NET Core:https://github.com/aspnet/home
  • ASP.NET Core文档:https://github.com/aspnet/Docs
  • EntityFramework Core框架:https://github.com/aspnet/EntityFrameworkCore
  • ASP.NET Core MVC框架:https://github.com/aspnet/Mvc
  • EntityFramework6:https://github.com/aspnet/EntityFramework6
  • .NET Framework源码:https://github.com/microsoft/referencesource
  • .NET Core基类库:https://github.com/dotnet/corefx
  • .NET Core CLR:https://github.com/dotnet/coreclr
  • Roslyn编译器:https://github.com/dotnet/roslyn
  • MVC5、Web API2、Web Pages3框架源码:https://github.com/aspnet/AspNetWebStack
  • .NET Standard:https://github.com/dotnet/standard
  • KestrelHttpServer用于ASP.NET Core的跨平台Web服务器:https://github.com/aspnet/KestrelHttpServer
  • Visual Studio Code源码:https://github.com/Microsoft/vscode
  • 一些优秀的.NET库、工具、框架、软件开源集合:https://github.com/quozd/awesome-dotnet
  • 一些常用框架对ASP.NET Core和.NET Core的支持报告:https://github.com/jpsingleton/ANCLAFS
  • 一些.NET下用于支持开发的开源项目集合:https://github.com/Microsoft/dotnet/blob/master/dotnet-developer-projects.md
  • 微软出品的分布式框架orleans:https://github.com/dotnet/orleans
  • ML.NET 用于.NET的开源和跨平台机器学习框架:https://github.com/dotnet/machinelearning

https://msdn.microsoft.com/zh-cn/library/dd393573.aspx、https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild

https://msdn.microsoft.com/en-us/library/dd409377.aspx 、https://www.zhihu.com/question/36413876)

比如 模块关系的代码图,可以看到各模块间的关系 

比如 对解决方案的代码度量分析结果 

比如 调试状态下 函数调用的 代码图,我们可以看到MVC框架的函数管道模型

以及并行堆栈情况、加载的模块、线程的实际情况

还有如进程、内存、反汇编、寄存器等的功能,这里不再一一展示

https://msdn.microsoft.com/zh-cn/library/b142f8e7(v=vs.110).aspx
有关项目模板: https://msdn.microsoft.com/zh-cn/library/ms247121(v=vs.110).aspx
有关项目元素的说明介绍:https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/16satcwx(v%3dvs.100)
有关调试更多内容:https://docs.microsoft.com/zh-cn/visualstudio/debugger/
有关代码设计建议:https://docs.microsoft.com/zh-cn/visualstudio/code-quality/code-analysis-for-managed-code-warnings
有关IntelliTrace介绍:https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/dd264915(v%3dvs.100)

https://docs.microsoft.com/zh-cn/aspnet/#pivot=core
Visual Studio IDE 指南:https://docs.microsoft.com/zh-cn/visualstudio/ide/
C# 指南: https://docs.microsoft.com/zh-cn/dotnet/csharp/
.NET指南:https://docs.microsoft.com/zh-cn/dotnet/standard/
微软开发文档:https://docs.microsoft.com/zh-cn/

最后送给大家我经常做的两句话:
1.先问是不是,再问怎样做,最后我一定会问 为什么
2.没人比谁差多少,相信自己,坚持不断努力,你也能成功

我喜欢和我一样的人交朋友,不被环境影响,自己是自己的老师,欢迎加群 .Net web交流群, QQ群:166843154 欲望与挣扎

作者:小曾
出处:https://www.cnblogs.com/1996V/p/9037603.html 欢迎转载,但请保留以上完整文章,在显要地方显示署名以及原文链接。
.Net交流群, QQ群:166843154 欲望与挣扎

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=367ug8kkmjk0s