|
| |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
我们知道, C#的语法与C++异常相似,实现从C++向C#的转换,其困难不在于语言本身,而在于认识.NET的可治理环境和对.NET框架的理解。 尽管C#与C++在语法上的变化是很小的,几乎不会对我们有什么影响,但有些变化却足以使一些粗心的C++编程人员时刻铭记在心。在本篇文章中我们将讨论C++编程人员最轻易犯的十个错误。 陷阱1: 没有明确的结束方式 假如使用非可治理性资源,在不使用这些资源后,必须明确地释放它。对资源的隐性控制是由Finalize方式(也被称为finalizer)提供的,当对象被销毁时,它就会被碎片收集程序调用收回对象所占用的资源。 finalizer 应该只释放被销毁对象占用的非可治理性资源,而不应牵涉到其他对象。假如在程序中只使用了可治理性资源,那就无需也不应当执行Finalize方式,只有在非可治理性资源的处理中才会用到Finalize方式。由于finalizer需要占用一定的资源,因此应当只在需要它的方式中执行 finalizer。 直接调用一个对象的Finalize方式是绝对不答应的(除非是在子类的Finalize中调用基础类的Finalize。),碎片收集程序会自动地调用Finalize。 从语法上看,C#中的destructor与C++异常相似,但其实它们是完全不同的。C#中的destructor只是定义Finalize方式的捷径。因此,下面的二段代码是有区别的: ~MyClass() MyClass.Finalize()
错误2:Finalize和Dispose使用谁? 假如已经使用了Dispose方式,则应当阻止碎片收集程序再对相应的对象执行Finalize方式。为此,需要调用静态方式 GC.SuppressFinalize,并将相应对象的指针传递给它作为参数,Finalize方式就能调用Dispose方式了。据此,我们能够得到如下的代码: public void Dispose() // 通知GC不要再调用Finalize方式 public override void Finalize() 对于有些对象,可能调用Close方式就更合适(例如,对于文件对象调用Close就比Dispose更合适),可以通过创建一个private属性的 Dispose方式和public属性的Close方式,并让Close调用Dispose来实现对某些对象调用Close方式。 由于不能确定一定会调用Dispose,而且finalizer的执行也是不确定的(我们无法控制GC会在何时运行),C#提供了一个Using语句来保证 Dispose方式会在尽可能早的时间被调用。一般的方式是定义使用哪个对象,然后用括号为这些对象指定一个活动的范围,当碰到最内层的括号时, Dispose方式就会被自动调用,对该对象进行处理。 using System.Drawing; } // 编译器将调用Dispose处理theFont对象 Font anotherFont = new Font(\"Courier\",12.0f); using (anotherFont) } // 编译器将调用Dispose处理anotherFont对象 } }
在本例的第一部分中,Font对象是在Using语句中创建的。当Using语句结束时,系统就会调用Dispose,对Font对象进行处理。在本例的第二部分,Font对象是在Using语句外部创建的,在决定使用它时,再将它放在Using语句内,当Using语句结束时,系统就会调用 Dispose。 Using语句还能防止其他意外的发生,保证系统一定会调用Dispose。 错误3:C#中的值型变量和引用型变量是有区别的 此外,C#语言还把变量分为值类型和引用类型。除非是被包含在一个引用类型中,值类型变量的值保留在栈中,这一点与C++中的变量异常相似。引用类型的变量也是栈的一种,它的值是堆中对象的地址,与C++中的指针异常地相似。值类型变量的值被直接传递给方式,引用型变量在被作为参数传递给方式时,传递的是索引。 类和界面可以创建引用类变量,但需要指出的是,结构数据类型是C#的一种内置数据类型,同时也是一种值型的数据类型。 错误4:注重隐性的数据类型转变 Boxing是隐性的,假如在需要索引型数据类型的地方使用了值型数据类型的变量,值型变量就会隐性地转化为索引型数据类型的变量。Boxing会影响代码执行的性能,因此应当尽量避免,尤其是在数据量较大的时候。 假如要将一个打包的对象转变回原来的值型变量,必须显性地对它进行解包。解包需要二个步骤:首先对对象实例进行检查,确保它们是由值型的变量被包装成的;第二步将实例中的值拷贝到值型变量中。为了确保解包成功,被解包的对象必须是通过打包一个值型变量的值生成的对象的索引。 using System; //打包 // 解包(必须是显性的)
错误5:结构与对象是有区别的 在C#中,结构只是一个用户自定义的数据类型,并不能取代类。尽管结构也支持属性、方式、域和操作符,但不支持继续和destructor。 更重要的是,类是一种索引型数据类型,结构是值型数据类型。因此,结构在表达无需索引操作的对象方面更有用。结构在数组操作方面的效率更高,而在集合的操作方面则效率较低。集合需要索引,结构必须打包才适合在集合的操作中使用,类在较大规模的集合操作中的效率更高。 错误6:虚方式必须被明确地覆盖 假如B公司的一位编程人员要在ListBox上添加一个Sort方式: public class ListBox : Window 在A公司发布新版的Window类之前,这不会有任何问题。假如A公司的编程人员也在Window类中添加了一个Sort方式。 public class Window 在C ++中,Windows类中的Sort方式将成为ListBox类中Sort方式的基础方式,在希望调用Windows类中的Sort方式时, ListBox类中的Sort方式就会被调用。在C#中,虚拟函数总是被认为是虚拟调度的根。也就是说,一旦C#发现一个虚拟的方式,就不会再在虚拟链中查找其他虚拟方式。假如ListBox再次被编译,编译器就会生成一个警告信息: \"/class1.cs(54,24): warning CS0114: \\\'ListBox.Sort()\\\' hides 要使当前的成员覆盖原来的方式,就需要添加override关健字,或者添加new关健字。 要消除警告信息,编程人员必须搞清晰他想干什么。可以在ListBox类中的Sort方式前添加new,表明它不应该覆盖Window中的虚方式: public class ListBox : Window 这样就可以清除警告信息。假如编程人员确实希望覆盖掉Window中的方式,就必须使用override关健字来显性地表明其意图。
错误7:类成员变量的初始化 Employee::Employee(int theAge, int theSalaryLevel): 这种方式在C#中是非法的。尽管仍旧可以初始化基础类,但象上面的代码那样对成员变量初始化就会引起编译错误。在C#中,我们可以在定义成员变量时的同时对它进行初始化: Class Employee : public Person 注重:必须明确地定义每个变量的访问权限。 错误8:布尔型变量与整型变量是两回事儿 在C#中,布尔型变量与整型变量并不一样,因此下面的代码是不准确的: if( someFuncWhichReturnsAValue() ) if someFuncWhichReturnsAValue返回零表示false,否则表示true的想法已经行不通了。这样的好处是原来存在的将赋值运算与相等相混淆的错误就不会再犯了。因此下面的代码: if ( x = 5 ) 在编译时就会出错,因为x=5只是把5赋给了X,而不是一个布尔值。 错误9:switch语句中会有些语句执行不到 switch (i)
switch (i) 假如case语句不执行任何代码,则所有的语句都会被执行。如下面的代码: switch (i) 错误10:C#中的变量要求明确地赋值 假如只是通过索引向方式传递一个变量,并且该变量是方式的输出变量,这是就会带来问题。例如,假设有一个方式,它返回当前时间的小时、分、秒,假如象下面这样编写代码: int theHour; 假如在使用theHour、theMinute和theSecond这三个变量之前没有对它们进行初始化,就会产生一个编译错误: Use of unassigned local variable \\\'theHour\\\' 我们可以通过将这些变量初始化为0或其他对方式的返回值没有影响的值,以解决编译器的这个小问题: int theHour = 0; 这样就有些太麻烦了,这些变量传递给GetTime方式,然后被改变而已。为了解决这一问题,C#专门针对这一情况提供了out参数修饰符,它可以使一个参数无需初始化就可以被引用。例如,GetTime中的参数对它本身没有一点意义,它们只是为了表达该方式的输出。在方式中返回之前,Out参数中必须被指定一个值。下面是经过修改后的GetTime方式: public void GetTime(out int h, out int m, out int s) 下面是新的GetTime方式的调用方式: timeObject.GetTime( out theHour, out theMinute, out theSecond);
返回类别: 教程 上一教程: 常见 Datagrid 错误 下一教程: 正弦函数的绘制的一种方式 您可以阅读与"C++编程人员轻易犯的10个C#错"相关的教程: · 从一个舆论调查的制作谈面向对象的编程思路(一) · Framework 类库的事件编程 · 在新的平台上编程 ----微软 .NET平台系列文章之一(译文/赵湘宁 ) · ASP.NET中Cookie编程的基础知识(4) · 使用 Visual C# .NET 在 ADO.NET 中以编程方法构建连接字符串 |
| 快精灵印艺坊 版权所有 |
首页 |
||