《由c++转向c#:我们需要注意哪些方面的变化》由会员分享,可在线阅读,更多相关《由c++转向c#:我们需要注意哪些方面的变化(23页珍藏版)》请在金锄头文库上搜索。
1、由 C+转向 C#:我们需要注意哪些方面的变化转自http:/ C+的语法和语义的,可以让 C 语言编程人员利用.NET 和通用语言运行库带来的便利。尽管从 C+转向 C#是相对容易的,但仍然有些地方值得我们注意。在这篇文章中我们将探索其中的一些新特性,如碎片收集、属性、foreach-loop 循环和界面等。每隔 10 年左右,编程人员就需要花费大量的时间和精力去学习新的编程技术。在 80 年代是 Unix 和 C,90 年代是 Windows 和 C+,现在又轮到了微软的.NETFramework 和 C#。尽管需要学习新的技术,但由此带来的好处却远高于付出的劳动。幸运的是,使用 C#和.
2、NET 进行的大多数工程的分析和设计与在 C+和 Windows 中没有本质的变化。在本篇文章中,我将介绍如何实现由 C+到 C#的飞跃。 已经有许多文章介绍过 C#对 C+的改进,在这里我就不再重复这些问题了。在这里,我将重点讨论由 C+转向 C#时最大的变化:由不可管理的环境向可管理的环境的变化。此外,我还会提出一些 C#编程人员容易犯的错误供大家参考,此外,还将说明一些 C#语言的能够影响编程的新功能。 转向可管理的环境 C+的设计目标是低级的、与平台无关的面向对象编程语言,C#则是一种高级的面向组件的编程语言。向可管理环境的转变意味着你编程方式思考的重大转变, C#不再处理细微的控制,
3、而是让架构帮助你处理这些重要的问题。例如,在 C+中,我们就可以使用 new 在栈中、堆中、甚至是内存中的某一特定位置创建一个对象。 在.NET 的可管理环境中,我们再不用进行那样细微的控制了。在选择了要创建的类型后,它的位置就是固定的了。简单类型(ints、double 和 long)的对象总是被创建在栈中(除非它们是被包含在其他的对象中),类总是被创建在堆中。我们无法控制对象是创建在堆中哪个位置的,也没有办法得到这个地址,不能将对象放置在内存中的某一特定位置。(当然也有突破这些限制的方法,但那是很另类的方法。)我们再也不能控制对象的生存周期,C#没有 destructor。碎片收集程序会将
4、对象所占用的内存进行回收,但这是非显性地进行的。 正是 C#的这种结构反映了其基础架构,其中没有多重继承和模板,因为在一个可管理的碎片收集环境中,多重继承是很难高效地实现的。 C#中的简单类型仅仅是对通用语言运行库(CLR)中类型的简单映射,例如,C#中的 int 是对System.Int32 的映射。C#中的数据类型不是由语言本身决定的,而是由 CLR 决定的。事实上,如果仍然想在C#中使用在 VisualBasic 中创建的对象,就必须使自己的编程习惯更符合 CLR 的规定。 另一方面,可管理的环境和 CLR 也给我们带来了好处。除了碎片收集和所有.NET 语言中统一的数据类型外,它还提供
5、给我们一个功能强大的面向组件的编程语言,无须对后期绑定提供特别的支持,类型发现和后期绑定都是被内置在语言中的。属性是 C#语言中的第一类的成员,事件和代理也是。 可管理环境最主要的优点是.NETFramework。尽管在所有的.NET 语文中都可以使用这种框架,但 C#可以更好地使用.NET 框架中丰富的类、接口和对象。 Traps C#看起来与 C+非常相似,这使得我们在由 C+转向 C#时比较轻松,但其中也有一些容易出错的地方。在C+中编写得非常漂亮的代码,在 C#中会不能通过编译,甚至会出现意想不到的结果。C#与 C+之间在语法上的变化并不大,编译器能够发现这二者之间大部分的差异,我在这
6、里就不再多费笔墨了,在这里我介绍几个容易出问题的比较重要的变化: 引用类型和值类型 在 C#中,值类型和引用类型数据是有区别的。简单类型(int、long、double 等)和结构属于值类型数据,类和对象属于引用类型数据。除非是包含在引用类型的变量中,与在 C+中一样,值类型变量的值存储在栈中。引用类型的变量也存储在栈中,但它的值是一个存储在堆中的对象的地址,这一点也与 C+ +类似。值类型变量是将自己的值传递给方法,而引用类型变量则将自己的指针传递给方法。 结构 C#中的结构与 C+中有非常明显的区别。在 C+中,结构更象是类,除了缺省的继承外,其缺省的访问权限是 public 而不是 pr
7、ivate。在 C# 中,结构与类截然不同,它是用来封装轻型对象的,是值类型的数据类型,在传递时传送的是变量的值,而不是其地址。此外,它们也有一些不适用于类的限制,例如,它是不能继承的,也没有除 System.ValueType 之外的基本类。结构还不能定义一个缺省的 constructor。 另一方面,由于结构比类的效率要高,因此它非常适合于创建轻型对象。因此,如果它的缺点对你的软件没有影响,使用结构比使用类效率要高得多,尤其是对于小对象而言。 所有的一切都是对象 在 C#中,所有的东西都是由继承 Object 得到的,包括创建的类和 int、structs 等值类型的变量。Object 类
8、提供了一些有用的方法,例如 ToString,使用 ToString 的一个例子是与 System.Console.WriteLine 一起使用,它可以接受一个字符串和许多对象。与使用 printf 语句不同,要使用 WriteLine,需要提供代换变量。假设myEmployee 是用户定义的 Employee 类的一个实例, myCounter 是用户定义的 Counter 类的一个实例: Console.WriteLine(“Theemployee:,thecountervalue:“,myEmployee,myCounter); 其中的 WriteLine 会调用每个对象的 Object
9、.ToString 方法,替换作为参数返回的变量。如果 Employee 类不覆盖 ToString,就会调用缺省的实现(由 System.Object 继承得到的),它将把类的名字作为一个字符串返回。Counter 会覆盖 ToString,返回一个整型的变量,因此,上面代码的输出为: Theemployee:Employee,thecountervalue:12 如果向 WriteLine 传递一个整型变量会发生什么情况呢?由于不能对整型变量调用 ToString,编译器将自动将整型变量封装在一个对象的实例中。当 WriteLine 调用 ToString 时,对象就会返回表示整型变量值的
10、字符串。下面的代码就说明了这个问题: 类的使用 usingSystem;/不覆盖 ToString 的类publicclassEmployee/覆盖了 ToString 的类publicclassCounterprivateinttheVal;publicCounter(inttheVal)this.theVal=theVal;publicoverridestringToString()Console.WriteLine(“CallingCounter.ToString()“);returntheVal.ToString();publicclassTesterpublicstaticvoidM
11、ain()/创建类的实例Testert=newTester();/调用非静态成员/(mustbethroughaninstance)t.Run();/演示调用 ToString 的非静态方法publicvoidRun()EmployeemyEmployee=newEmployee();CountermyCounter=newCounter(12);Console.WriteLine(“Theemployee:,thecountervalue:“,myEmployee,myCounter);intmyInt=5;Console.WriteLine(“Herearetwointegers:and“
12、,17,myInt); 引用型参数和输出型参数 与 C+中相同,C#中的方法也只能有一个返回值。在 C+中,我们通过将指针或索引作为参数而克服了这个限制,被调用的方法改变其中的参数,调用方法就可以得到新的值了。 向方法中传递一个索引作为参数时,只能严格地按传递索引或指针所能够提供的方式访问原来的对象。对于值类型变量而言,就不能采用这种方法了。如果要通过引用型参数传递值型变量,就需要在其前面加上 ref 关健字。如下所示: publicvoidGetStats(refintage,refintID,refintyearsServed) 需要注意的是,既需要在方法的定义中使用 ref 关健字,也需
13、要在对方法的实际调用中使用 ref 关健字。 Fred.GetStats(refage,refID,refyearsServed); 现在,我们可以在调用方法中定义 age、ID 和 yearsServed 变量,并将它们传递给 GetStats,得到改变后的值。 C#要求明确的赋值,也就是说,在调用 GetStats 方法之前,必须对 age、ID 和 yearsServed 这三个局部变量进行初始化,这一工作似乎有点多余,因为我们仅仅使用它们从 GetStats 中得到新的变量的值。为了解决这一问题,C#提供了 out 关健字,表示我们可以向方法中传递没有被初始化的变量,这些变量将通过引用
14、变量的方式进行传递: publicvoidGetStats(outintage,outintID,outintyearsServed) 当然了,调用方法也必须作出相应的变化: Fred.GetStats(outage,outID,outyearsServed); New 的调用 在 C+中,new 关健字可以在堆上生成一个对象。在 C#中却不是这样。对于引用类型变量而言,new 关健字在堆上生成一个对象;对于结构等值类型变量而言,new 关健字在栈中生成一个对象,并需要调用constructor。 事实上,我们可以不使用 new 关健字而在栈上生成一个结构类型的变量,但这时需要注意的是,New
15、 关健字能够初始化对象。如果不使用 new,则在使用前必须手工地对结构中的所有成员进行初始化,否则在编译时会出错。 对象的初始化 usingSystem;/有二个成员变量和一个构造器的简单结构publicstructPointpublicPoint(intx,inty)this.x=x;this.y=y;publicintx;publicinty;publicclassTesterpublicstaticvoidMain()Testert=newTester();t.Run();publicvoidRun()Pointp1=newPoint(5,12);SomeMethod(p1);/fine
16、Pointp2;/不调用 new 而直接创建/编译器编译到这里时会出错,因为 p2 的成员变量没有被初始化/SomeMethod(p2);/手工对它们进行初始化p2.x=1;p2.y=2;SomeMethod(p2);/一个可以接受 Point 作为参数的方法privatevoidSomeMethod(Pointp)Console.WriteLine(“Pointatx“,p.x,p.y);属性 大多数的 C+编程人员都希望使成员变量的属性为 private,这种隐藏数据的想法促进了数据封装概念的出现,使我们能够在不改变用户依赖的接口的情况下而改变类的实现。通常情况下,我们只希望客户获取或设置这些成员变量的值。因此,C+编程人员开发出了用来存取 private 成员变量的存取器。 在 C#中,属性是类的第一级成员。对于客户而言,属性看