非安全代码(Unsafe code):一般而言,用VB.NET, C#编译成的代码是安全代码,这里的安全是指编译器本身的能力而言。比如对同样的一个C#程序,如果使用/unsafe选项进行编译的话,会产生如下的directive:
.assembly assemblyNameXXX
{
// 涉及到安全许可时,忽略代码校验
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
}
// 此定制属性表明了非安全代码
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
对JIT来说,在编译为本机代码时,忽略代码校验。
有一点需要注意,非安全代码并不是说你的代码不“安全”,而是指从编译器到CLR无法保证或不负责代码的安全而已。
对于C++/CLI,只有/clr:safe编译选项才是安全代码。/clr:pure与C#中的/unsafe等同。而/clr选项为C++/CLI所特有。
传统意义上的C++代码统称为本地代码(native code)。本地代码当然是一种非安全代码。
托管代码(Managed Code):可以编译为中间语言(Intermediate Lanauage)的代码。与之相对的是非托管代码(Unmanaged Code)。对VB.net和C#而言,只能编译为托管代码。而C++/CLI则可将编译为托管代码和非托管代码的混合体。
托管数据(Managed Data):在托管堆上分配内存并由垃圾处理器负责回收的数据。
C++/CLI的四个面向CLR的编译选项:
- /clr:oldSyntax
兼容.NET 1.0 & 1.1的一种扩展语法,一般称为Managed Extension for C++。可以说是MS在.NET到来后,准备扩展C++的一种尝试。它不属于CLI的一部分。在以后的编译环境中可能会被淘汰。
- /clr
第一个符合CLI的C++扩展。用此编译选项可以产生混合代码。
/clr:pure
可以包含非托管数据,但不能包含非托管代码。
/clr:safe
只能包含托管代码和托管数据。
为什么需要C++/CLI?
就我的经验而言,对/clr:pure和/clr:safe编译选项而言,我更喜欢用C#来实现,无论从代码的优雅还是编程习惯或个人偏好来讲。C#也是微软在.net平台上主推的一门语言。唯一的区别仅是语法不同而已。一般而言,新的语言总能综全先前的一些语言的优点再加以扩展,因此更具有时代特征。还有在新的.NET 2.0,C++/CLI不允许开发Web应用程序,但可以用来开发WebService程序。
但C++/CLI毕竟有自己的"法宝"--/clr编译选项可以产生混合代码,也就是可以将托管和非托管共存。别小瞧这个功能,这个功能非常有用。
- 相信大多数公司都有一些旧的C++代码。在C++大行其道的时代,我们在C++上已经进行了大量投资,也许也产生了不少稳定的产品。在.NET大潮汹涌的今天,我们有必要重写这些代码吗?当然没有必要,要知道Legacy代码,并非指代码有问题,相反大多数这样的代码是成熟的产品,也经过了多外的检测。如果重写的话,不说工作量有多少,Bug肯定会引入不少,还要重新进行测试。可以说是出力不讨好。
- .NET的出现不会把C++逼入绝境,在一些对速度有要求的场合如算法的实现,模式的识别,驱动程序等,还得要C++。任意语言都不是完美的。虽然我们都在追求完美,但是完美并不存在。所以我们也要进行一些权衡。
- 有时我们需要的第三方软件只有C++接口,我们没有源代码,所以我们没有重写代码的可能。但我们通过C++/CLI可以写一个Wrapper来供.NET使用。
- 有时出于代码安全性考虑,把一些敏感算法用非托管代码实现,毕竟托管代码很容易被反编译。
公共语言运行时(CLR):
早在.NET出现之前,就有类似的概念,如VB6.0中的msvbvm60.dll,以及在java世界中的JVM(Jave Virtual Machine)。.net正是咨询和综合了业界的在这方面的经验,而开发出来的一个为.NET提供加载、校验、执行以及提供一些基础服务的运行时环境。当然,它也是对操作系统的抽象,也就是说,它的目标也是"Write once, run anywhere"。现在也有一些开源的项目在尝试在linux等平台上也提供类似的运行时环境,典型的如mono(http://www.mono-project.com/Main_Page)。