比较Java和C#时,不可避免地会注意到两者的相似性,这部分是缘于两者共同的老祖宗:C和C++。但是,当James Gosling率领他的团队开发Java时,不仅从C++那里借鉴了大量功能,而且更重要的是,他们摒弃了C++中容易出错和难以学习的特性。C#的设计者也像Java那样添加了大量C++特性,只是忘了移除C++的一些不好的特性。结果就是一种试图为任何人做任何事的语言,造成内部容易产生冲突,而且极度复杂。
在流程控制和语法中最容易挑出错误。C#提供了goto命令,用于更改程序的执行点。但早在1968年由Edsger W. Dijkstra发表的“Go To语句有害论”一文中,计算机科学家便已齐声反对goto。goto造成代码难以调试,而且难以通过测试覆盖(test coverage)工具。
而且和一般看法不同的是,运算符重载具有同样的缺陷,而且它造成的错误更难以发现。如果'+'依据操作数的类型而具有不同的含义,那么代码的运行就不再是透明的,会出现大量不可预料的副作用。
C#提供了一个简单的机制,可将部分代码标记为unsafe(不安全)。在这些不安全区域中,由Java和C#所提供的防止程序员直接改变内存位置以及使用指针算术的安全机制会暂时失效,代码的安全性将受到质疑。但是,在采用了垃圾回收机制的高级语言中,如果下降到内存地址一级上进行操作,不可避免地会妨碍内部的对象/内存隔离。就像在C和C++中已经臭名昭著的那样,这很容易引入错误,调试会变成一场噩梦,缓冲区溢出会再次泛滥,造成许多安全漏洞。
C#还允许简单地访问主机系统上的原生库。“与非.NET对象绑定”类似于Java原生接口(JNI)所提供的功能,只是前者更危险。JNI通过良好定义的接口,小心限制了Java代码和原生代码之间的交互。相反,.NET虽然大幅简化了对原生对象文件的调用,但开发者如果滥用这一功能,很容易就会破坏平台间的移植性。
C#和.NET中的大多数组件都同SOAP Web服务紧密集成。SOAP是使用XML来指定参数和结果值,并发出远程过程调用的一项出色标准。但它并不是你惟一的选择。使用为Web服务设计的扩展库,Java开发者可轻松改变其Web服务的形式,可将其变成SOAP、XML-PRC或者其他尚未发明的任何东西。当然,C#开发者也能选择为非SOAP
Web服务提供的外部库,但SOAP标准的紧密集成更像是一种限制,而非改进。