大雀软件园

首页 软件下载 安卓市场 苹果市场 电脑游戏 安卓游戏 文章资讯 驱动下载
技术开发 网页设计 图形图象 数据库 网络媒体 网络安全 站长CLUB 操作系统 媒体动画 安卓相关
当前位置: 首页 -> 技术开发 -> 其他相关 -> C++编程人员容易犯的10个C#错误

C++编程人员容易犯的10个C#错误

时间: 2021-07-31 作者:daque

咱们领会, c#的语法与c++特殊一致,实行从c++向c#的变化,其艰巨不在乎谈话自己,而在乎熟习.net的可处置情况和对.net框架的领会。 纵然c#与c++在语法上的变革是很小的,简直不会对咱们有什么感化,但有些变革却足以使少许大略的c++编制程序职员功夫铭刻在意。在本篇作品中咱们将计划c++编制程序职员最简单犯的十个缺点。 组织1: 没有精确的中断本领 简直不妨实足确定地说,对于大普遍c++编制程序职员而言,c#与c++最大的各别之处就在乎碎片搜集。这也表示着编制程序职员再也无需担忧外存揭发和保证简略一切没有效的南针。但咱们再也没辙透彻地遏制杀死无效的东西这个进程。究竟上,在c#中没有精确的destructor。 即使运用非可处置性资源,在不运用那些资源后,必需精确地开释它。对资源的隐性遏制是由finalize本领(也被称为finalizer)供给的,当东西被废弃时,它就会被碎片搜集步调挪用收回东西所占用的资源。 finalizer该当只开释被废弃东西占用的非可处置性资源,而不应牵扯到其余东西。即使在步调中只运用了可处置性资源,那就无需也不该当实行finalize本领,惟有在非可处置性资源的处置中才会用到finalize本领。因为finalizer须要占用确定的资源,所以该当只在须要它的本领中实行finalizer。 径直挪用一个东西的finalize本领是一致不承诺的(只有是在子类的finalize中挪用普通类的finalize。),碎片搜集步调会机动地挪用finalize。 从语法上看,c#中的destructor与c++特殊一致,但本来它们是实足各别的。c#中的destructor不过设置finalize本领的捷径。所以,底下的二段代码是有辨别的: ~myclass()   {   // 须要实行的工作   } myclass.finalize()   {   // 须要实行的工作   base.finalize();   } 缺点2:finalize和dispose运用谁? 从上头的阐明中咱们仍旧很领会,显性地挪用finalizer是不承诺的,它只能被碎片搜集步调挪用。即使蓄意尽量地开释少许不复运用的数目有限的非可处置性资源(如文献句柄),则该当运用idisposable界面,这一界面有个dispose本领,它不妨帮你实行这个工作。dispose是无需等候finalize被挪用而不妨开释非可处置性资源的本领。 即使仍旧运用了dispose本领,则该当遏止碎片搜集步调再对相映的东西实行finalize本领。为此,须要挪用静态本领gc.suppressfinalize,并将相映东西的南针传播给它动作参数,finalize本领就能挪用dispose本领了。据此,咱们不妨获得如次的代码: public void dispose()   {   // 实行整理操纵 // 报告gc不要再挪用finalize本领   gc.suppressfinalize(this);   } public override void finalize()   {   dispose();   base.finalize();   } 对于有些东西,大概挪用close本领就更符合(比方,对于文献东西挪用close就比dispose更符合),不妨经过创造一个private属性的dispose本领和public属性的close本领,并让close挪用dispose来实行对某些东西挪用close本领。 因为不许决定确定会挪用dispose,并且finalizer的实行也是不决定的(咱们没辙遏制gc会在何时运转),c#供给了一个using语句来保护dispose本领会在尽大概早的功夫被挪用。普遍的本领是设置运用哪个东西,而后用括号为那些东西指定一个震动的范畴,当遇到最内层的括号时,dispose本领就会被机动挪用,对该东西举行处置。 using system.drawing;   class tester   {   public static void main()   {   using (font thefont = new font("arial", 10.0f))   {   //运用thefont东西 } // 编写翻译器将挪用dispose处置thefont东西 font anotherfont = new font("courier",12.0f); using (anotherfont)   {   // 运用anotherfont东西   } // 编写翻译器将挪用dispose处置anotherfont东西   }   } 在本例的第一局部中,font东西是在using语句中创造的。当using语句中断时,体例就会挪用dispose,对font东西举行处置。在本例的第二局部,font东西是在using语句外部创造的,在确定运用它时,再将它放在using语句内,当using语句中断时,体例就会挪用dispose。 using语句还能提防其余不料的爆发,保护系一致定会挪用dispose。 缺点3:c#中的值型变量和援用型变量是有辨别的 与c++一律,c#也是一种强典型编制程序谈话。c#中的数据典型被分为了二大类:c#谈话自己所固有的数据典型和用户自设置数据典型,这一点也与c++一致。 其余,c#谈话还把变量分为值典型和援用典型。只有是被包括在一个援用典型中,值典型变量的值保持在栈中,这一点与c++中的变量特殊一致。援用典型的变量也是栈的一种,它的值是堆中东西的地方,与c++中的南针特殊地一致。值典型变量的值被径直传播给本领,援用型变量在被动作参数传播给本领时,传播的是索引。 类和界面不妨创造援用类变量,但须要指出的是,构造数据典型是c#的一种内置数据典型,同声也是一种值型的数据典型。 缺点4:提防隐性的数据典型变换 boxing和unboxing是使值型数据典型被看成索引型数据典型运用的二个进程。值型变量不妨被包装进一个东西中,而后再被解包回值型变量。囊括内置数据典型在前的一切c#中的数据典型都不妨被隐性地变化为一个东西。包装一个值型变量就会天生一个东西的范例,而后将变量正片到范例中。 boxing是隐性的,即使在须要索引型数据典型的场合运用了值型数据典型的变量,值型变量就会隐性地变化为索引型数据典型的变量。boxing会感化代码实行的本能,所以该当尽管制止,更加是在数据量较大的功夫。 即使要将一个打包的东西变换回从来的值型变量,必需显性地对它举行解包。解包须要二个办法:开始对东西范例举行查看,保证它们是由值型的变量被包装成的;第二步将范例中的值正片到值型变量中。为了保证解包胜利,被解包的东西必需是经过打包一个值型变量的值天生的东西的索引。 using system;   public class unboxingtest   {   public static void main()   {   int i = 123; //打包   object o = i; // 解包(必需是显性的)   int j = (int) o;   console.writeline("j: {0}", j);   }   }[page_break]即使被解包的东西是失效的,或是一个各别数据典型东西的索引,就会爆发invalidcastexception异外。 缺点5:构造与东西是有辨别的 c++中的构造与类差不离,独一的辨别是,在缺省状况下,构造的考察权力是public,其接受权力也是public。少许c++编制程序职员将构造动作数据东西,但这不过一个商定而非是必需如许的。 在c#中,构造不过一个用户自设置的数据典型,并不许代替类。纵然构造也扶助属性、本领、域和操纵符,但不扶助接受和destructor。 更要害的是,类是一种索引型数据典型,构造是值型数据典型。所以,构造在表白无需索引操纵的东西上面更有效。构造在数组操纵上面的功效更高,而在汇合的操纵上面则功效较低。汇合须要索引,构造必需打包才符合在汇合的操纵中运用,类在较大范围的汇合操纵中的功效更高。 缺点6:虚本领必需被精确地掩盖 在c#谈话中,编制程序职员在掩盖一个虚本领时必需显性地运用override关健字。假如一个window类是由a公司编写的,listbox和radiobutton类是由b公司的和编制程序职员在购置的a公司编写的window类的普通上编写的,b公司的编制程序职员对囊括window类将来的变革情景在前的安排知之甚少。 即使b公司的一位编制程序职员要在listbox上增添一个sort本领: public class listbox : window   {   public virtual void sort() {"}   } 在a公司颁布新版的window类之前,这不会有任何题目。即使a公司的编制程序职员也在window类中增添了一个sort本领。 public class window   {   // "   public virtual void sort() {"}   } 在c++中,windows类中的sort本领将变成listbox类中sort本领的普通本领,在蓄意挪用windows类中的sort本领时,listbox类中的sort本领就会被挪用。在c#中,假造因变量老是被觉得是假造安排的根。也即是说,一旦c#创造一个假造的本领,就不会再在假造链中搜索其余假造本领。即使listbox再次被编写翻译,编写翻译器就会天生一个劝告消息: "\class1.cs(54,24): warning cs0114: ‘listbox.sort()‘ hides   inherited member ‘window.sort()‘. 要使暂时的分子掩盖从来的本领,就须要增添override关健字,大概增添new关健字。 要取消劝告消息,编制程序职员必需搞领会他想干什么。不妨在listbox类中的sort本领前增添new,表白它不该当掩盖window中的虚本领: public class listbox : window   {   public new virtual void sort() {"}  如许就不妨废除劝告消息。即使编制程序职员真实蓄意掩盖掉window中的本领,就必需运用override关健字来显性地表白其企图。 缺点7:类分子变量的初始化 c#中的初始化与c++中各别。假如有一个带有private本质的分子变量age的person类,employee是由接受person类而天生的,它有一个private本质的salarylevel分子变量。在c++中,咱们不妨在employee的结构器的初始化局部初始化salarylevel,如底下的代码所示: employee::employee(int theage, int thesalarylevel):   person(theage) // 初始化普通类   salarylevel(thesalarylevel) // 初始化分子变量   {   // 结构器的代码   } 这种本领在c#中利害法的。纵然仍旧不妨初始化普通类,但象上头的代码那么对分子变量初始化就会惹起编写翻译缺点。在c#中,咱们不妨在设置分子变量时的同声对它举行初始化: class employee : public person   {   // 分子变量的设置   private salarylevel = 3; // 初始化   } 提防:必需精确地设置每个变量的考察权力。 缺点8:布尔型变量与整型变量是两码事儿 if( somefuncwhichreturnsavalue() ) 在c#中,布尔型变量与整型变量并不沟通,所以底下的代码是不精确的: if( somefuncwhichreturnsavalue() ) if somefuncwhichreturnsavalue归来零表白false,要不表白true的办法仍旧行不通了。如许的长处是从来生存的将赋值演算与十分相污染的缺点就不会累犯了。所以底下的代码: if ( x = 5 ) 在编写翻译时就会堕落,由于x=5不过把5赋给了x,而不是一个布尔值。 缺点9:switch语句中会有些语句实行不到 在c#中,即使一个switch语句实行了少许操纵,则步调就大概不许实行到下一个语句。所以,纵然底下的代码在c++中是正当的,但在c#中却不对法: switch (i)   {   case 4:   callfuncone();   case 5: // 缺点,不会实行到这边   callsomefunc();   } 要实行上头代码的手段,须要运用一个goto语句: switch (i)   {   case 4:   callfuncone();   goto case 5;   case 5:   callsomefunc();   } 即使case语句不实行任何代码,则一切的语句城市被实行。如底下的代码: switch (i)   {   case 4: // 能实行到   case 5: // 能实行到   case 6:   callsomefunc();   } 缺点10:c#中的变量诉求精确地赋值 在c#中,一切的变量在运用前都必需被赋值。所以,不妨在设置变量时不对它举行初始化,即使在把它传播给一个本领前,必需被赋值。 即使不过经过索导向本领传播一个变量,而且该变量是本领的输入变量,这是就会带来题目。比方,假如有一个本领,它归来暂时功夫的钟点、分、秒,即使象底下如许编写代码: int thehour;   int theminute;   int thesecond;   timeobject.gettime( ref thehour, ref theminute, ref thesecond) 即使在运用thehour、theminute和thesecond这三个变量之前没有对它们举行初始化,就会爆发一个编写翻译缺点: use of unassigned local variable ‘thehour‘   use of unassigned local variable ‘theminute‘   use of unassigned local variable ‘thesecond‘ 咱们不妨经过将那些变量初始化为0或其余对本领的归来值没有感化的值,以处置编写翻译器的这个小题目: int thehour = 0;   int theminute = 0;   int thesecond = 0;   timeobject.gettime( ref thehour, ref theminute, ref thesecond) 如许就有些太烦恼了,那些变量传播给gettime本领,而后被变换罢了。为领会决这一题目,c#特意对准这一情景供给了out参数化装符,它不妨使一个参数无需初始化就不妨被援用。比方,gettime中的参数对它自己没有一点意旨,它们不过为了表白该本领的输入。在本领中归来之前,out参数中必需被指定一个值。底下是过程窜改后的gettime本领: public void gettime(out int h, out int m, out int s)   {   h = hour;   m = minute;   s = second;   } 底下是新的gettime本领的挪用本领: timeobject.gettime( out thehour, out theminute, out thesecond); 

热门阅览

最新排行

Copyright © 2019-2021 大雀软件园(www.daque.cn) All Rights Reserved.