从 C# 迁移到 Java 还是有不习惯的地方,虽然 C# 受到的最大批评就是“抄袭 Java”。看来 C# 还是相对优雅(如果 BCL 能小一点就好了)。话说从 VB .NET 扩展到 C# 的时候我也曾经觉得 VB .NET 好,所以当时的项目 C# 只用来处理 unchecked
。现在我觉得 C# 如果写核心库不随便上 GUI 的话还是不错的,特别喜欢 unchecked
、lock
、unsafe
的设计。
刚上手不习惯的有:
- 没有
delegate
,用内部类实现观察者模式实在是太不优雅了,而且Callable
这种东西实现更困难了。 - 所有自定义类型都是 class,而且只能传递引用副本,不存在 ValueType +
ref
。没有 struct 意味着用类似值类型的方法交互时要不断地clone()
。 - byte 是有符号的(陷阱!),所有基元数值类型都是有符号的(CLS 规定的值类型中,
Byte
无符号,Int16
/Int32
/Int64
有符号,更符合习惯)。(注:SByte
、UInt16
、UInt32
、UInt64
虽然在 C# 和 VB .NET 中可用,但是不符合 CLS。) - 发生的异常未必是 throws 声明的,例如对
HttpExchange
的getRequestHeaders()
进行add()
实际上会触发NotSupportedOperationException
,但是Headers
基类型没有显式抛出该异常。 - 封装类型(
Integer
/Long
etc)和基元数值类型(int
/long
etc)不等价,而且封装类型之间不存在继承。bencode 库中我修改了对整数的解析(从Integer
到Long
,因为 BEncoding 规范是如此),但是运行报错不能将Integer.valueOf()
的结果赋给Long
——直至我使用不怎么友善的Number
类型作为赋值类型才正常。 - 泛型类型擦除,都收缩到了
Object
,再加上默认虚函数,导致IEquatable<T>
这种接口实际上是不能实现的(IEquatable<T>
声明了一个bool Equals(T)
的方法,C# 中通过自动插入类型+重载解决,Java 中会直接覆盖Object
的equals(Object)
);- 动态类型变长数组创建不可能,
Array.newInstance()
需要传递一个Class<?>
,但是T.class
非法,所以难以获得 T 的类型(Hibernate 中似乎有方案,不过对于现在的我来说太复杂)。
今天去审查,保安很和蔼,出来的时候还问事情办好了没有。