zhaichao

2017-04-23 14:39 425人阅读 评论(0) 收藏 举报

版权声明:本文为博主原创文章,未经博主允许不得转载。

做Unity项目已经有一年多了,知道Unity用Mono来实现跨平台,但是对于.net .net framework和mono一直只是一知半解。最近在做一个Unity项目需要从外部动态加载场景以及脚本,于是乎对.net framework和mono仔细研究了一发,这里也做一点总结。不过水平有限,如有错误求轻喷。
首先看一下github上.net core项目的主页,大概了解一下.net是干嘛的:
可以看到这个主页下面有几个子项目,其中有几个名字看上去很熟悉,比如coreclr,不就是CLR虚拟机么,corelx,看描述像是提供FCL的,cli,耳熟能详的通用语言基础结构,另外还有一个standard项目,里面是关于.net Standard方面的内容,Standard项目中有一个关于Standard version的文档:
另外在Standard项目的Readme中有如下描述:
所以可以总结一下,.net从一个抽象上来说其实是一个理念,即使得多种语言编写的程序能够通过一个通用的runtime运行在不同的操作系统以及硬件平台上。但光有理念不行,还需要实现,我们这里把对于.net里面的某个实现叫做.net platform(比如.net framework就是一个在windows上实现的.net platform,mono则是一个跨平台的.net platform)。一个.net platform想要达成.net的目标,就需要一些组件,比如上图中CLR通用语言运行时,比如FCL基础类库,比如各种语言的编译器,编译器编译出来的东西想要能在CLR中运行,那也需要遵循一定的标准,这就是CLI和CIL,CIL规定了编译输出的规则,而CLI规定了编译器输入语言的规则,只有符合这种标准的语言才能编译成CIL语言运行在CLR中。
好了现在有了CIL和CLR,程序员可以用符合CLI的语言比如C#编写程序了,然后将其编译成CIL,最后在CLR中运行。但是问题来了,程序员开发程序的时候需要用到一些功能以及数据结构,不可能所有的功能细节都自己实现,不然开发成本也太高了,所以就需要提供一些基础类库,方便程序员进行开发,那么需要提供哪些基础类库呢?这也需要一个标准,而.Net Standard就是用于这个目的,它规定了某个.net platform需要提供哪些API给开发者。这样的话加入一个开发者在.net platform A(比如.net framework)上开发了一个项目,然后想迁移到.net platform B(比如Mono)上,那么只要两个platform实现了同一个.net standard那么源代码就无需修改可以直接编译运行。
不过还有一个问题,假如我有一台机器,装了.net platform A(比如.net framework)和.net platform B(比如Mono),那么我在A上编译出来的一个.net程序放到B上可以运行么?理论上应该没问题,毕竟CIL是统一的,虽然一个是A的CLR一个是B的CLR,但是它们都是用来处理CIL程序,就像java代码编译出来既可以运行在JVM上也可以运行在delvik上一样。然而实际上不一定,因为CIL本身也不是一成不变的,它也有自己的版本,看下面这个文档:
里面的表格详细说明了.net framework和CLR版本之间的关系,从.net framework 2.0到3.5使用的是CLR 2.0,.net framework 4.0以后使用的是CLR 4.0,中间没有CLR 3.0版本。这也就意味着CIL语言本身也在发生变化,面向CLR 4.0编译出来的程序自然是不能运行在CLR 2.0上的。
说那到底什么是.net framework呢?个人理解从抽象角度说.net framework是对.net标准(这个标准具体包括CLI,CIL,.net standard等)在windows平台上的一套实现,具体上说.net framework包含一整套解决方案,包含许多字组件,比如编译器、CLR、FCL等等,其中每个组件都有自己的版本,比如编译器有自己的版本用于适应不同版本的语言,比如.net framework 3.5的编译器只支持到C# 3.0,最新已经到C# 7.0了;每个版本的.net framework提供的FCL也在不断丰富,比如System.LINQ到.net framework 3.5才有;CLR的版本也会不同,之前已经说过了。因此.net framework的版本其实就是其组件版本的一个集合,高版本的.net framework中的每个子组件都进行了一定的版本更新。
其实正常来说.net framework只是对.net标准的一套实现而已,其他的对于.net标准的实现完全可以将各种不同版本的组件组合起来用,比如我一套.net platform提供了.net framework 4.0的FCL和面向C# 6.0的编译器,但用的是CLR 2.0的运行时,这并没有什么问题,只要编译器和运行时匹配就行了(mono就是这么干的)。但是由于.net是微软提出来的而且.net framework是微软开发的,那别的.net platform实现自然就已.net framework为标杆,每个版本的.net framework都提供了一些新的features,支持.net framework x.x就是说这个.net platform实现了x.x版本.net framework的特性,比如下面是mono主页上的文档:
  
可以看到上面说的是.net 4.6 4.5,这里表示的其实是.net framework,这个图片的意思就是最新版本的mono已经实现了.net framework 4.6中支持C# 6的特性,以及此外还可以发现只有.net 3.5和2.0是mono完全实现了其所有特性。准确的说其实是mono实现了.net
framework的大部分feature,并且还提供了一些mono自己的class library。Mono和.net framework大致有一个对应关系,如这篇文章所说:http://www.cnblogs.com/zhaoqingqing/archive/2016/08/12/5762867.html
这个表似乎不完全正确,mono 2.0实现了System.LinQ组件,这个组件在.net 3.5中提供,所以mono 2.0对应的应该是.net 2.0/3.5,即两者之和。不过还是可以当做一个参考。所以说加入一个程序集是用.net framework 3.5构建的,引用了一些dll如system.core以及system.linq,那么要想把其导入mono项目中,就必须保证mono的版本高于2.0,不然会找不到相应的引用。
还有一点需要注意,网上很多讲.net版本的时候讲.net framework version和CLR version混为一谈,有些时候说的.net 2.0指的其实是CLR 2.0。另外有些人把System.Environment.Version误以为是.ne framework版本,其实不是,msdn上说的很明确,这个值指的是CLR的版本:
另外还有一点值得注意,在vs中构建一个.net framework 3.5的项目时是,引用的System.dll是在系统的.net v2.0目录下的,也就是说.net framework不是独立的,而是依赖于.net framework 2.0.不过.net 4.0以后的版本好像就不是这样了,每次新版本都是独立的。
最后谈一下Unity,Unity为了跨平台使用了Mono,其使用的Mono版本可以通过代码或者命令行方式获得,unity forum上已经有牛人说明了:
我自己的测试结果是mono 2.0
查了一下mono官网,mono 2.0是08年的老古董(Unity居然还在用,貌似是版权问题,没有深究),而用vs打开一下Unity中的脚本,查看一下项目构建文件.csproj:
可以看到Unity用的是.net 3.5,所以难道Unity的脚本是用.net framework 3.5构建的?显然不是。
我们知道vs有一个东西叫VSTU,它最大的作用就是可以用vs的断点调试功能调试Unity Editor。Unity中的脚本在vs中打开的时候会构建一个VSTU项目。VSTU项目虽然跟普通VS项目看上去很像,但其实VSTU项目本质上并不是真正的vs项目,如果你右键项目->属性是没有反应的(VSTU 2.1以前有反应,之后就禁用了),而且右键项目中的引用也不会有添加引用选项,其实VSTU是把vs当做了一个功能强大的编辑器。
但VSTU不只是利用了VS进行语法检查这么简单,它的另一个作用就是断点调试。在没有断点调试的情况下,Unity使用自己的编译器进行编译,生成Assembly-CSharp.dll(在/Library/目录中),点击Play按钮的时候用的是这个dll,而用VS进行断点调试的时候则会用VS的编译器编译出Assembly-CSharp.dll以及pdb文件,在\Temp\UnityVS_obj\Debug\目录中,此时点击Play用的就是这个dll。当然build出exe的时候用的还是自己的编译器。
VSTU对项目进行了限制,不能直接在VS中添加新的dll,但可以拷贝到Unity项目的Asset目录下,这样Unity会重新构建VSTU项目,把拷进去的dll显示在引用列表里面。
VSTU构建的项目是基于.net framework 3.5的。因为Unity用的是mono 2.0啊,mono 2.0实现的feature包括.net framework 2.0和3.5,而UnityEngine.dll引用了System.Core.dll,而这个dll在.net framework 3.5才有,如果是是基于.net framework 2.0构建,那么第一有些mono
2.0支持的feature在vs里面就会找不到,另外也无法断点调试,因为编译通不过。
其实也可以在Unity的安装目录中寻找一些端倪,在windows下为:
C:\Program Files\Unity\Editor\Data\Mono\lib\mono\2.0
这个目录2.0目测就是mono的版本,目录中有很多dll,比如System.*.dll,这说明unity自带了mono项目,提供了mono 2.0中实现的基础类库。虽然Unity的脚本可以在像VS以及MonoDeveloper中打开,但是在build的时候用的还是Unity自带的Mono中的编译器,而Mono 2.0仅支持到C# 3.0,所以有些最新的语法在Unity里面是无法编译通过的(Unity
5.3.5 p8提供了一个新的编译器mono 4.4用于测试,但是似乎没有下文了)。
总结一下就是,Unity使用的是mono 2.0,支持C# 3.0,提供与.net framework 3.5/2.0 API兼容的类库(mono 2.0实现了.net framework 2.0 + 3.5的feature,但是没有实现.net framework 3.0的WPF的feature,所以官网的说法是.Net
2.0/3.5 framework profile
),使用了与CLR 2.0兼容的mono runtime,因此用vs构建Unity的dll需要.net framework 3.5以下,不然runtime不兼容;如果要用到UnityEngine等Unity的功能必须用.net framework 3.5这个版本,不然vs项目找不到System.Core.dll,无法通过编译,如果只是一些工具类,不需要引用UnityEngine.dll,那么用.net framework 2.0构建是可以的。vs只是一个第三方构建工具,想要构建出Unity能用的dll就不能使用Unity(Mono
2.0)不支持的feature。
最后有一点之前一直在困扰我,但今天稍微有点想通了,就是Unity的Player Setting里面有个API compability Level:
这个只有两个选项:.Net 2.0和.Net 2.0 Subnet,这个说实话让人很不解,从字面上讲是指API兼容,那兼容到.net 2.0难道是指兼容.net framework 2.0的FCL API?但Unity可以用到.net framework 3.5的一些库啊。网上找了一通以后发现了如下网址:
以及这个Question:
其中有一句话很关键:
The 2.0 there is likely a good reflection of what you have at least
所以梳理一下就是.Net 2.0和.Net 2.0 Subnet是指编写的C#代码能够引用的函数集合的不同,如果选择了subset那么dll就不会被导入到项目中来。比如同一个项目用.Net 2.0和.Net 2.0 Subnet构建出来的目录如下,可以很明显看到两者的差别。
   
当新建一个Unity项目时,只会有一些核心的dll会被导入到项目中,其他的dll需要从外部拷贝到项目的Asset文件夹下,VSTU项目中是不能直接添加引用的,个人感觉VSTU对项目的限制有点多,像是把开发者当成傻子,因为你在用Unity那么这些功能就给你禁用掉,不过目测可以通过修改.sln或者.csproj文件来实现一些特殊需要。那.net
framework 3.5呢?其实Unity支持的是.net framework 2.0 + 3.5,跳过了3.0,因为3.0是WPF的,Unity不需要,.net 2.0指的是你至少可以用哪些feature。
Unity最近因为加入了.Net基金会,出了几个用最新mono的测试版:
Unity 5.5.0 b4里面API compability Level增加了一个4.6选项,其实是把原来的mono 2.0换成mono 4.6进行测试,mono 4.6支持C# 6.0,并且开发者可以使用.net 4.6的API写程序,然而也不知道什么时候能有稳定版。而且mono都快要被淘汰了,以后目测都是IL2CPP了。

扒一扒.net、.net framework、mono和Unity的更多相关文章

  1. linux2.6.24内核源代码分析(2)——扒一扒网络数据包在链路层的流向路径之一

    在2.6.24内核中链路层接收网络数据包出现了两种方法,第一种是传统方法,利用中断来接收网络数据包,适用于低速设备:第二种是New Api(简称NAPI)方法,利用了中断+轮询的方法来接收网络数据包, ...

  2. linux2.6.24内核源代码分析(1)——扒一扒sk_buff

    最近研究了linux内核的网络子系统上的网络分组的接收与发送的流程,发现这个叫sk_buff的东西无处不在,内核利用了这个结构来管理分组,在各个层中传递这个结构,因此sk_buff可以说是linux内 ...

  3. View绘制详解(三),扒一扒View的测量过程

    所有东西都是难者不会,会者不难,Android开发中有很多小伙伴觉得自定义View和事件分发或者Binder机制等是难点,其实不然,如果静下心来花点时间把这几个技术点都研究一遍,你会发现其实这些东西都 ...

  4. 扒一扒ReentrantLock以及AQS实现原理

    提到JAVA加锁,我们通常会想到synchronized关键字或者是Java Concurrent Util(后面简称JCU)包下面的Lock,今天就来扒一扒Lock是如何实现的,比如我们可以先提出一 ...

  5. 扒一扒.NET Core的环境配置提供程序

    很久之前,在玩Docker的时候顺便扒了扒,最近,终于下定决心花了些时间整理并成文,希望能够给大家一些帮助. 目录 .NET Core中的配置 ASP.NET Core中的配置 扒一扒环境变量提供程序 ...

  6. 扒一扒EOS的前世今生

    扒一扒EOS的前世今生 EOS是什么?   EOS可以认为是Enterprise Operation System的缩写,即商用的一款分布式区块链操作系统,EOS主要为了解决百万级用户的使用问题,为企 ...

  7. ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案 try.dot.net 的正确使用姿势 .Net NPOI 根据excel模板导出excel、直接生成excel .Net NPOI 上传excel文件、提交后台获取excel里的数据

    ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案   ASP.NET Core 从2.2版本开始,采用了一个新的名为Endpoint的路由方案,与原来的方案在使用上差别不 ...

  8. jQuery源码学习扒一扒jQuery对象初使化

    神奇的jQuery可以这样玩jQuery("#id").css()或 jQuery("#id").html() 这么玩jQuery("#id" ...

  9. 扒一扒MathType不为人知的技巧

    MathType作为一款编辑数学公式的神器,很多人在使用它时只是很简单地使用了一些最基本的模板,很多功能都没有使用.MathType功能比你想象中的大很多,今天我们就来扒一扒MathType那些不为人 ...

  10. 扒一扒asp.net core mvc控制器的寻找流程

    不太会排版,大家将就看吧. asp.net core mvc和asp.net mvc中都有一个比较有意思的而又被大家容易忽略的功能,控制器可以写在非Web程序集中,比如Web程序集:"MyW ...

随机推荐

  1. C#替换文件中特定字符串,按照原来的编码格式保存

    private void button1_Click(object sender, EventArgs e) { var txt1 = "E:\\Temp\\local"; str ...

  2. POJ 2368 Buttons

    题目链接:http://poj.org/problem?id=2368 Bash game (巴什博弈):当K是(L+1)的倍数时可以确保second player赢.所以这道题要找的就是在K的因子中 ...

  3. Spring+MVC Controller层接收App端请求的中文参数乱码问题。

    在正文之前,说明下Filter的作用: 过滤器顾名思义就是进行过滤的,可以实现代码的定向执行和预处理.通俗点说法filter相当于加油站,request是条路,response是条路,目的地是serv ...

  4. sql中varchar(n),nvarchar(n) 长度性能及所占空间分析

    sql中varchar(n),nvarchar(n) 长度性能及所占空间分析 1.varchar(n),nvarchar(n) 中的n怎么解释: nvarchar(n)最多能存n个字符,不区分中英文. ...

  5. LD的-rpath,-rpath-link

    http://blog.chinaunix.net/uid-24709751-id-3563351.html http://songzhangzhang.blog.163.com/blog/stati ...

  6. Swift 加载 xib 崩溃问题

    新版本用 Swift开发 遇到的坑 解决方法

  7. 做seo应该如何选择网站程序?

    网站程序:(具体网站案例,可在官网看到)绝大多数情况下,我们将做的网站有以下几种1.个人博客,推荐的程序Wordpress(php的程序,比较强大),Zblog(asp的程序,比较简单)2.门户网站( ...

  8. BERT(Bidirectional Encoder Representations from Transformers)

    BERT的新语言表示模型,它代表Transformer的双向编码器表示.与最近的其他语言表示模型不同,BERT旨在通过联合调节所有层中的上下文来预先训练深度双向表示.因此,预训练的BERT表示可以通过 ...

  9. update_or_create()

    update_or_create(默认值=无,** kwargs)¶ 使用给定更新对象的便捷方法,kwargs必要时创建新对象.这defaults是用于更新对象的(字段,值)对的字典.值中的值defa ...

  10. String StringBuilder StringBuffer区别

    String StringBuilder StringBuffer String类是final类,不可以被继承,且它的成员方法也是final方法,当一个字符串对象进行操作操作时,任何的改变不会影响到这 ...