`
tomhibolu
  • 浏览: 1382381 次
文章分类
社区版块
存档分类
最新评论

C#中C/C++程序员注意问题

 
阅读更多

1、C/C++程序员请注意,不能在case语句不为空时“向下执行”。

  2、值类型和引用类型之间的区别:C#的基本类型(int,char等)都是值类型,是在栈中创建的。而对象是引用类型,创建于堆中,需要使用关键字new。

  3、在C#中通过实例访问静态方法或成员变量是不合法的,会生成编译器错误。但是我们可以通过声明他们的类的名字来发访问静态成员。

  4、C#派生类中,没有私有或者保护继承。关于这一点C++程序员注意了。

  5、C#多态性,C++程序员注意,必须显式用关键自override标记重新定义了虚方法的方法声明。

  6、抽象类与密封类,抽象类用来被派生,并为其子类提供遵循模版;而密封类则完全不允许被派生。抽象类关键字是abstract;密封类关键字为sealed

  7、C#中结构体的定义与C++的非常不同。在C++中,结构体与类除了默认的可见性(一个是public,一个是privae)之外完全一样。而在C#中,结构体是值类型,而类是引用类型。

  8、C#中委托相当于C++中的方法指针,关键字为delegate。

  9、.NET用来创建网页程序的技术是ASP.NET2.0,它在命名空间System.Web和System.Web.UI中为创建网页程序提供了一套丰富的类型。

  10、C#线程三种同步机制:互锁类(Interlocked),C# lock语句,以及监控器对象(Monitor class)

  11、C#中要使用值变量之前,需要事先声明,并且要在使用之前先设置初始值,永远不可为null;引用类型变量,存储在heap中,不允许在初始化之前使用这个变量。

  12、C#中switch-case语句与C/C++不同地方在于C#中不允许case判断式“silent fall through”。也就是说,当找到符合case标记后的常数后,只会执行此case区块中的程序代码,不会再执行其他的case判断式进行判断的动作。

  13、参数传入机制

  14、C#中使用数组要注意两件事情:数组名称不可置于中括号前方;声明数组变量时,不能够指定数组的大小。

  15、类

  C#的成员访问修饰符包含以下几种:

  Public

  任何外部的类都可以不受限制的存取这个类的方法和数据成员。

  Private

  类中的所有方法与数据成员只能在此类中使用,外部无法存取。

  Protected

  除了让本身的类可以使用之外,任何继承自此类的子类都可以存取。

  Internal

  在同一个.NET Assembly(Application或Library,也就是说,同一个EXE或同一个DLL中的成员)中都可以存取。

  Protected internal

  只限定目前的项目,或是继承自此类的成员才可以存取。

  结构与类的差异:

  16、值类型与引用类型之间的互换称为Boxing与Unboxing

  17、在C#中,对象都是使用new保留字建立的,建立对象时分两个步骤:

  一、向系统要求内存。

  二、调用构造器进行初始化。

  18、C#中多态性,虚拟方法用来指明扩展类可以改写基础类方法的实现部分。多态性用override、new来实现,在C++中用virtual来实现。

  Override方法则是应用在扩展类当中,可使用override保留字指明欲改写基础类的virtual成员之实现部分。换言之,virtual方法是在基础类中定义的,而override是在扩展类中定义的。

  方法声明前加上了virtual 修饰符,我们称之为虚方法,反之为非虚。使用了virtual 修饰符后,不允许再有static, abstract, 或override 修饰符。

  19、接口(Interface)和类(Class)非常相似,唯一的不同点在于接口中不包含任何实现程序代码。注意:定义在接口中的方法隐含都是属于public,因此不能够在方法之前加public修饰符。

class B

  { public virtual void foo () {} }

  class D : B

  {

  public override void foo () {}

  }

  class N : D

  {

  public new void foo () {}

  public static void Main() {

  N n = new N ();

  n.foo( ) ; // 调用N的foo

  ((D)n).foo( ) ; // 调用D的foo

  ((B)n).foo( ) ; // 调用D的foo

  }

  }


  20、attribute属性

  Attribute不过是一个声明式的标记,能在执行时期将一些信息,如类、数据结构、enum以及assembly等信息,传送给.NET执行时期引擎,以动态个更改对象执行时期的行为。不妨将attribute想象成一个可供程序保存、然后使用的注释。

  21、反射

  反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

  反射在下列情况下很有用:

  当需要访问程序元数据中的属性时。请参见主题使用反射访问属性。

  检查和实例化程序集中的类型。

  在运行时构建新类型。使用 System.Reflection.Emit 中的类。

  执行后期绑定,访问在运行时创建的类型的方法。请参见主题动态加载和使用类型。

  22. 显示转换 向下转型(数据截取)

  显示转换与C,C++中不同,C#中当显示转换时,编译器(开启checked选项)检查到超出转换后类型的值域而发生的溢出则会抛出异常(OverflowException),其余情况发生数据截取或者精度丢失。Float到double, decimal大到无法表示或是无穷和NaN则抛出异常InvalidCastException。

  显示引用转化包括:

  a. 从对象到任何引用类型

  b. 从类类型到S到类类型T,其中S是T的基类

  c. 从类类型S到接口类型T,其中S不是密封类,而且没有实现T

  d. 从接口类型S到类类型T,其中T不是密封类,而且没有实现S

  e. 从接口类型S到接口类型T,其中S不是T的子接口

  f. 从元素类型Ts的数组类型S到元素类型Tt的数组类型T的转换,而且这种转换满足条件:

  i. S和T只有元素类型不同,而维数相同

  ii. Ts和Tt都是引用类型

  iii. 存在从Ts到Tt的显示引用转换

  iv. 从System.Array到数组类型

  v. 从System.Delegate到代表类型

  vi. 从System.ICloneable到数组类型或者代表类型

  为了确保显示引用转换的正常进行,要求源变量的值必须为null或者他所引用的对象的类型可以被隐式引用转换转换为目标类型。否则显示引用转换失败,抛出InvalidCastException异常。

  注意:不论是显示引用转换还是隐式引用转换,只改变引用类型,而不改变引用类型指向的数据值的类型。

  23.as操作符,通过引用转换或者装箱转换将一个值显示的转换成指定的引用类型。As操作符不会产生任何异常,如果转换不可以进行,则结果值为null

  格式 Expresstion(表达式) as Type(引用类型)

  24.checked 和 unchecked操作符,用于整形运算时控制当前环境中的溢出检查,如果溢出则抛出OverflowException异常。

  注意:checked和unchecked检查异常,只对之后的表达式检查,而不对之后括号中的函数调用内部进行检查.

  25.C#中switch语句中各case后如果不加break或者goto语句,不会像C,C++中那样继续执行下一个case,将会报错。

  可以用 goto case 值/default进行跳转

  在C,C++中switch-case语句只能对整形或者字符型变量有效,对字符串不可使用,而在C#中可以在switch-case语句中使用字符串常量,且case标签中允许null值。

  26.C#在流程控制中多了一个foreach关键字

  foreach语句表示收集一个集合中的各元素,并针对各个元素执行内嵌语句。

  语句格式:

  foreach(类型 + 标识符(循环变量) + in(关键字) + 表达式) 嵌套语句

  每执行一次内嵌语句,循环变量就依次取集合中的一个元素带入其中。

  此处的循环变量是一个只读型局部变量,如果试图改变它的值或将它作为一个ref或者out类型的参数传递,都会引发编译错误。

  foreach中表达式是一个集合类型,如果该集合的元素类型与循环变量类型不一致,则必须有一个显示定义的从集合中的元素类型到循环变量元素类型的显示转换。

  在C#中集合类型的语法定义:

  (1) 该类型必须支持一个形为GetEnumerator()的公有的非静态方法,该方法的返回类型为结构,类或者接口。

  (2) 形为GetEnumerator()的方法返回的结构,类或者接口应当包含一个公有的非静态方法MoveNext(),该方法的返回类型为布尔值

  (3) 形为GetEnumerator()的方法返回的结构,类或者接口应当包含一个公有的非静态的属性Current(其类型称为集合的元素类型),该属性可以读出。

  [数组支持foreach]

  27.C#没有独立的预处理器,C# 中的预处理指令仅仅用来和C,C++保持一致,而并不是编译器开始编译代码之前的一个单独的处理步骤,它是作为词法分析的一部分来执行的。

  #define #undef应该放在任何非预处理指令之前.

  C#中预处理指令如果出现在其他输入输出元素的中间就不会被执行。

  如此程序试图在Debug时显示 He is a doctor,否则显示He is a teacher 

using System;

  class myprog{

  static void main(){

  Console.WriteLine(@”He is a

  #if Debug

  doctor

  #else

  teacher

  #endif

  “);

  }

  }


  结果输出却为

  He is a

  #if Debug

  doctor

  #else

  teacher

  #else

  28.C#与C++异常处理的不同之处

  1).在C#中,所有异常都表现为一个类的实例,这个类继承自System.Exception类。而在C++中,任何类型的任何值都可以表示异常。

  2).C#中一个终结块里的终结代码既可以在正常情况下执行,也可以在异常情况下执行,而在C++中,不复制代码是难以做到的。

  3).在C#中,系统级的异常,如溢出,除数为0等,由于有定义完好的异常类因而可以等同于应用程序及错误条件。

  29.异常相关

  引发异常的条件:

  1).throw语句无条件,即时地抛出异常。

  2).C#语句和表达式执行过程中激发了某个异常的条件,使得操作无法正常结束,从而引发异常。

  throw语句抛出异常: throw expresstion()

  30.C#类定义之后无分号

  31.C#中使用internal修饰符修饰的类成员对于同一包中的应用程序或库是透明的,而在包.net之外是禁止访问的。

  32.C#中this关键字在类中是引用类型,是类对象自身的引用,而在C++中是指针,指向当前类对象。

  32.C#中使用名字空间时using后没有namespace关键字,而在C++中需要使用using namespace

  33.C#中类静态(static)成员不需要在类外进行定义,而在­C++中静态在类中进行声明,在类外进行定义,但是不管在这两种语言中任何一种中,静态成员都为所有类对象共同拥有,无论存在多少该类的对象,静态成员在内存中只有一个。

  34.C++中允许显示调用析构函数,而在C#中不允许对析构函数进行显示调用。

  35.C#中没有全局变量,全局函数,全局常量的概念,在C#中所有的变量,方法必须封装在类中。

  36.C#中用ref声明引用参数,使用引用参数时不另开辟内存区域,但是需要初始化。

  用out声明输出参数,out修饰符后的参数不需要初始化,作为函数返回值来使用。

  37.形参中包含了数组型参数,那么它必须在参数表中位于最后。另外,参数只允许是一维数组。比如,string[]和string[][]类型都可以作为数组参数,而string[ , ]则不能,而且数组型参数不能用ref, out修饰。

  38.C#中readonly修饰符表示此作用域为只读域,readonly标识后只能在类的构造函数和域的定义中进行修改,其他情况下只读。

  在C++中使用#define,const定义常量可以在C#中用static+readonly来替代。(注意:const与static+readonly区别在于,const的值在编译时生成,而static+readonly知道程序运行时才形成。)

  39.C#中声明后的变量都将有默认初始值,包括自定义的结构。(任何引用的默认初始值为null)域的初始化分为两种形式:对于静态域,类在装载时对其进行初始化;对于非静态域,在类的实例创建时进行初始化。在默认的初始化之前,域的值是不确定的。

  40.使用abstract修饰的抽象属性,set,get中只有一个分号“;”。

  get访问器用return获取值,set用value设置值。

  

  41.事件(event)是类或对象用来“发出通知”的成员,通过提供事件的句柄,客户能够把事件和可执行代码联系在一起。

  事件的声明中可以包含事件访问说明,或者依靠编译器自动提供一个访问器;它也可以省略事件访问说明,一次定义一个或多个事件。

  注意:使用abstract修饰符的抽象事件必须省略事件访问说明,否则编译器会提示错误。

  事件所声明的类型必须是一个代表(delegate)类型,代表类型应预先声明。

  事件的预定是通过为事件加上+=操作符实现的,如 okButton.Click += new EventHandler(okButtonClick) (其中okButtonClick为单击事件的处理函数。)只要事件被触发,方法就会被调用。

  事件的撤销则采用左操作符“-=”实现的。

  对事件的触发相当于调用事件所表示的原型----delegate,所以对delegate型原型的调用必须先经过检查,确保delegate不是null型的。

  如果每个事件的存储开销太大,就可以在类中包含事件访问声明,按私有成员的规则存放事件句柄列表。访问器的声明包括两种:添加访问器声明(add)和删除访问器声明(remove)。(在执行预定操作时使用添加型访问器,在执行撤销操作时使用删除型访问器。访问器中实际上还包含了一个名为value的隐藏的参数。不管是哪种事件访问器,都对应相应的一个方法,这个方法只有一个事件类型的值参数,摒弃返回值为void。)

  关于class EventArgs: 此类不包含事件数据,在事件引发时不向事件处理程序传递状态信息的事件会使用此类。如果事件处理程序需要状态信息,则应用程序必须从此类派生一个类来保存数据。

  42.C#中索引指示器实际与C++中重载下标运算符”[]”类似;并用get和set定义对被索引的元素的读写权限。

  如: 
  43.C#中继承时在派生类前加上继承类型的关键字(public/private/protected),而在C++中继承时,此类关键字写在需要继承的基类之前,冒号之后。

  44.C#中派生类继承基类后,若声明与基类成员同名的成员,编译器会警告,可使用new关键字关闭警告,但此时并不覆盖继承的成员。(如果使用new关键字,但是并没有重名的现象,则编译器会警告。不能载声明一个成员时同时使用new和override关键字。)

  45.在C#中base作为关键字保留,用于派生类调用基类成员时简化书写。

  46.C#中抽象类使用abstract修饰符,不能被实例化;而C++中抽象类是指包含纯虚函数(函数之后加有”=0”并且没有函数体)的类。

  C#中抽象类不能同时又是密封的。

  C#中抽象类作为基类,在派生类继承抽象类时,必须通过重载来实现所有继承而来的抽象成员,否则派生类也为抽象类。

  抽象方法是用abstract修饰的方法,和C++中纯虚函数一样,他没有函数体。

  抽象方法在派生类中不能使用base关键字来进行访问。

  47.C#中如果想让一个类不能被继承,则可以使用sealed关键字修饰,密封类可以保证编写的类不被继承。(密封类由于不再有派生类,其中用virtual修饰的方法被转化为非虚的,virtual关键字在密封类中不再生效。)

  用sealed修饰的方法称为密封方法,不能被继承。(不是类的每个成员方法都可以作为密封方法,密封方法必须对基类的虚方法进行重载,提供具体的实现方法。因此,sealed修饰符总是和override修饰符同时使用。)

  48.从技术上来看,接口是一组包含了函数型方法的数据结构。

  接口继承和类继承不同:

  1).类继承不仅是说明继承,而且也是实现继承;而接口继承只是说明继承。派生类可以继承基类的方法实现,而派生的接口只继承了成员方法说明,而没有继承父接口的实现。

  2).C#中类继承只允许单继承,但是在接口继承中允许多重继承。(逗号分隔多个父接口。Private或者internal类型的接口是不允许的,被继承的接口应该是可以访问的。)

  接口可以包含一个或多个成员,成员可以使方法、数型、索引指示器和事件,但不能是常量、域、操作符、构造函数或析构函数,而且不能包含任何静态成员。

  接口成员默认访问方式是public,接口成员在声明时不能包含任何修饰符,如abstract, public, protected, internal, private, virtual, override, static等修饰符。(但是可以使用new修饰符)接口成员中允许函数重载,继承而来的成员不用再声明,接口可以定义与继承而来的成员同名的成员来覆盖继承而来的成员。

  当接口因为多重继承而产生成员重名的现象是,必须显示转化(指定)为相应的父接口(显示类型转换)来调用相应的成员。

  类实现接口的声明方式类似继承:

class BaseClass{}

  interface IMyClass {

  void Fun();

  void Fun(int arg);

  void Fun2();

  }

  class MyClass : IMyClass{

  void Fun(){…函数体…} //实现IMyClass中的Fun()方法

  Void Fun(int arg){…函数体…}

  ……

  }

  //还允许在继承的同时加入接口的实现声明

  如 public class MyClass2 : BaseClass, IMyClass //继承BaseClass并且实现IMyClass

  {

  ……

  }


  注意:接口本身不提供所定义的成员的实现,它仅仅说明这些成员,这些成员必须依靠实现接口的类或其他接口的支持。(借腹生子)(实现接口的成员时不能加任何访问限制符。)

  同一接口在不同类中的实现可以不同。

  隐式实现接口成员时,需要在成员声明起始处加上访问修饰符(public, private,protected等),此修饰符与接口声明的访问修饰符相同。并且隐式声明的接口成员可以通过类或者接口的实例调用,而显示声明的不能通过类实例调用,只能通过接口实例调用(显示声明实现接口成员时不需要加访问修饰符)。

  49.在C#中struct中成员和class成员默认的访问权限都是private;而在C++中struct的成员默认为public,而class中成员默认为private。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zcj_harbin/archive/2010/01/19/5208964.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics