1,不彻底的abstract
即使是abstract class,也不能对实现的接口的某个成员视而不见,即下面这样是不允许的:
interface in_one{
void A();
}
abstract class base_one : in_one{
}
这一点上还是Java方便,不管C#的初衷是什么
2,out参数与指针的指针
out子类不能转化为out基类,如果允许转换的化,将无法保证类型安全性;即out参数相当于指针的指针,而父类的指针与子类的指针是没有继承关系的,所以不能转化
3,强制针对接口编程
针对接口编程只是一个一般性的原则,但C#提供了一种机制,强迫客户程序员根据接口来引用你的实现类:重写接口成员时使用全名称,并且去掉public修饰
interface A{
void a();
}
class A_Sub:A {
void A.a() {
}
}
static void Main(string[] args)
{
((A)new A_Sub()).a(); //OK!
new A_Sub().a(); //Error!
}
4,@ 取消转义
取消字符串转义尚可理解,不过连关键字都变成普通标识了,实在看不出有多大意义
5,struct的构造函数
自定义的ctor并不能隐藏默认的无参构造函数,稍有意外,却也在情理之中,默认无参构造函数对于struct有良好定义的语义
6,const,readonly
const相当于C++的static const
readonly相当于C++的const
所以,const相当于static readonly
7,自然的boxing,unboxing
string s = "abc";
object o = s;
int i = 123;
object o = i;
对于string的例子都不会吃惊,为什么要特殊对待int的例子呢?string是System.String的别名,只要把int当作System.Int32的别名,一切不都很自然了吗?int确实是System.Int32的别名,int和string还是有区别的,boxing后的值会被复制
8,智能的自定义转型
C++不允许一次转换中调用超过一次的自定义转型操作符,C#同样不允许,不同的是C#会在调用自定义转型操作符前后为源类型和目标类型各插入一次自动寻找的标准转型操作,如果需要的话;简单的说;
9,操作符重载
C++里内存由程序员管理,允许重载new操作符,C#则理所当然的禁止了对new的重载
C++里算术运算符+-*/等重载后,其结合形式+=,-=,*=,/=不会被自动重载,C#为了保证语义一致性,自动重载了它们的结合形式
C++里短路逻辑运算符&&,||重载后不再具有短路的特性,C#干脆禁止了对它们的重载,只能通过以下形式变通:
class Test {
public static bool operator false(Test test){
return false;
}
public static bool operator true(Test test){
return false;
}
public static Test operator & (Test lhs, Test rhs){
return lhs;
}
public static Test operator | (Test lhs, Test rhs){
return lhs;
}
static void Main(string[] args)
{
if(new Test() && new Test()){
}
}
}
10,作用域
与Java有点不一样,嵌套块中名称相同的标识符都必须引用相同的实体,这项规则保证一个表达式上下文中名称的意义在一个块中是相同的:
class Test
{
double x;
void F(bool b) {
x = 1.0;
if (b) {
int x = 1;
}
}
}
是错误的,因为x在外部块中(在if语句中包含嵌套块的扩展)引用了不同的实体。相反,例子
class Test
{
double x;
void F(bool b) {
if (b) {
x = 1.0;
}else {
int x = 1;
}
}
}
是允许的,因为名称x在外部块中永远不会使用