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. Sublime text 2/3 [Decode error - output not utf-8] 完美解决方法

    原文链接 http://blog.csdn.net/bbdxf/article/details/25594703 [Decode error - output not utf-8]或者[Decode  ...

  2. PNP的学习-P3P

    PNP方法是为了解决在当前两帧图像中,已知前一帧图像上的3dLandmark点和当前帧的2d特征点,求取当前帧的pose. PNP主要有P3P.EPNP.UPNP.DLT.MRE(LS Iterati ...

  3. java39

    String a= "hello.a.java;b.java;hello.java;hello.toha;"; //将每个分号的内容取出来 String[] res=a.split ...

  4. django.db.utils.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: ...

    出现此问题的解决方法: 在mysql中创建一个和settings.py里设置的mysql  'name'名字一样的数据库就可以了.

  5. python语法之函数2

    高阶函数: def f(n): return n*n def foo(a,b,func): func(a)+func(b) ret=func(a)+func(b) return ret foo(1,2 ...

  6. 使用mybatis plus 操作数据库

    mybatis plus 是基于mybatis 的一个增强包,比 mybatis 更加容易使用. 特点: 1.分页支持 2.支持自定义查询. 3.简单的情况下,不需要写map.xml 文件 4.支持租 ...

  7. python模块:subprocess

    # subprocess - Subprocesses with accessible I/O streams # # For more information about this module, ...

  8. 理解RNN

    摘自:https://zybuluo.com/hanbingtao/note/541458 语言模型就是这样的东西:给定一个一句话前面的部分,预测接下来最有可能的一个词是什么. 语言模型是对一种语言的 ...

  9. Android缩放动画[ScaleAnimation]

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); s ...

  10. vue数据更新UI不刷新显示解决方案

    vue比较常见的坑就是数据(后台返回)更新了,但是UI界面并没有更新,常见于以下情况: 一.数据为数组时1.通过数组索引修改数组元素例如: 此时UI数据并不会刷新 2.修改数组长度时: 解决方案: 如 ...