欢迎来到冰点文库! | 帮助中心 分享价值,成长自我!
冰点文库
全部分类
  • 临时分类>
  • IT计算机>
  • 经管营销>
  • 医药卫生>
  • 自然科学>
  • 农林牧渔>
  • 人文社科>
  • 工程科技>
  • PPT模板>
  • 求职职场>
  • 解决方案>
  • 总结汇报>
  • ImageVerifierCode 换一换
    首页 冰点文库 > 资源分类 > DOCX文档下载
    分享到微信 分享到微博 分享到QQ空间

    C#常见的10个错误及解决方法.docx

    • 资源ID:16537395       资源大小:25.73KB        全文页数:15页
    • 资源格式: DOCX        下载积分:5金币
    快捷下载 游客一键下载
    账号登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录
    二维码
    微信扫一扫登录
    下载资源需要5金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP,免费下载
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    C#常见的10个错误及解决方法.docx

    1、C#常见的10个错误及解决方法关于C#C#是达成微软公共语言运行库(CLR)的少数语言中的一种。达成CLR的语言可以受益于其带来的特性,如跨语言集成、异常处理、安全性增强、部件组合的简易模型以及调试和分析服务。作为现代的CLR语言,C#是应用最为广泛的,其应用场景针对Windows桌面、移动手机以及服务器环境等复杂、专业的开发项目。C#是种面向对象的强类型语言。C#在编译和运行时都有的强类型检查,使在大多数典型的编程错误能够被尽早地发现,而且位置定位相当精准。相比于那些不拘泥类型,在违规操作很久后才报出可追踪到莫名其妙错误的语言,这可以为程序员节省很多时间。然而,许多程序员有意或无意地抛弃了这

    2、个检测的有点,这导致本文中讨论的一些问题。关于本文本文描述了10个 C# 程序员常犯的错误,或应该避免的陷阱。尽管本文讨论的大多数错误是针对 C# 的,有些错误与其他以 CLR 为目标的语言,或者用到了Framework Class Library(FCL) 的语言也相关。常见错误 #1: 把引用当做值来用,或者反过来C+ 和其他很多语言的程序员,习惯了给变量赋值的时候,要么赋单纯的值,要么是现有对象的引用。然而,在C# 中,是值还是引用,是由写这个对象的程序员决定的,而不是实例化对象并赋值的程序员决定的。这往往会坑到 C# 的新手程序员。如果你不知道你正在使用的对象是否是值类型或引用类型,你

    3、可能会遇到一些惊喜。例如:Pointpoint1=newPoint(20,30);Pointpoint2=point1;point2.X=50;Console.WriteLine(point1.X);/20(doesthissurpriseyou?)Console.WriteLine(point2.X);/50Penpen1=newPen(Color.Black);Penpen2=pen1;pen2.Color=Color.Blue;Console.WriteLine(pen1.Color);/Blue(ordoesthissurpriseyou?)Console.WriteLine(pen2

    4、.Color);/Blue如你所见,尽管Point和Pen对象的创建方式相同,但是当一个新的X的坐标值被分配到point2时,point1的值保持不变。而当一个新的color值被分配到pen2,pen1也随之改变。因此,我们可以推断point1和point2每个都包含自己的Point对象的副本,而pen1和pen2引用了同一个Pen对象。如果没有这个测试,我们怎么能够知道这个原理?一种办法是去看一下对象是如何定义的(在Visual Studio中,你可以把光标放在对象的名字上,并按下F12键)publicstructPoint/definesa“value”typepublicclassPen

    5、/definesa“reference”type如上所示,在C#中,struct关键字是用来定义一个值类型,而class关键字是用来定义引用类型的。对于那些有C+编程背景人来说,如果被C+和C#之间某些类似的关键字搞混,可能会对以上这种行为感到很吃惊。如果你想要依赖的行为会因值类型和引用类型而异,举例来说,如果你想把一个对象作为参数传给一个方法,并在这个方法中修改这个对象的状态。你一定要确保你在处理正确的类型对象。常见的错误#2:误会未初始化变量的默认值在C#中,值得类型不能为空。根据定义,值的类型值,甚至初始化变量的值类型必须有一个值。这就是所谓的该类型的默认值。这通常会导致以下,意想不到的

    6、结果时,检查一个变量是否未初始化:classProgramstaticPointpoint1;staticPenpen1;staticvoidMain(stringargs)Console.WriteLine(pen1=null);/TrueConsole.WriteLine(point1=null);/False(huh?)为什么不是【point 1】空?答案是,点是一个值类型,和默认值点(0,0)一样,没有空值。未能认识到这是一个非常简单和常见的错误,在C#中很多(但是不是全部)值类型有一个【IsEmpty】属性,你可以看看它等于默认值:Console.WriteLine(point1.I

    7、sEmpty);/True当你检查一个变量是否已经初始化,确保你知道值未初始化是变量的类型,将会在默认情况下,不为空值。常见错误#3: 使用不恰当或未指定的方法比较字符串在C#中有很多方法来比较字符串。虽然有不少程序员使用=操作符来比较字符串,但是这种方法实际上是最不推荐使用的。主要原因是由于这种方法没有在代码中显示的指定使用哪种类型去比较字符串。相反,在C#中判断字符串是否相等最好使用Equals方法:publicboolEquals(stringvalue); publicboolEquals(stringvalue,StringComparisoncomparisonType);第一个E

    8、quals方法(没有comparisonType这参数)和使用=操作符的结果是一样的,但好处是,它显式的指明了比较类型。它会按顺序逐字节的去比较字符串。在很多情况下,这正是你所期望的比较类型,尤其是当比较一些通过编程设置的字符串,像文件名,环境变量,属性等。在这些情况下,只要按顺序逐字节的比较就可以了。使用不带comparisonType参数的Equals方法进行比较的唯一一点不好的地方在于那些读你程序代码的人可能不知道你的比较类型是什么。使用带comparisonType的Equals方法去比较字符串,不仅会使你的代码更清晰,还会使你去考虑清楚要用哪种类型去比较字符串。这种方法非常值得你去使

    9、用,因为尽管在英语中,按顺序进行的比较和按语言区域进行的比较之间并没有太多的区别,但是在其他的一些语种可能会有很大的不同。如果你忽略了这种可能性,无疑是为你自己在未来的道路上挖了很多“坑”。举例来说:strings=strasse;/outputsFalse:Console.WriteLine(s=straße);Console.WriteLine(s.Equals(straße);Console.WriteLine(s.Equals(straße,StringComparison.Ordinal);Console.WriteLine(s.Equals(St

    10、raße,StringComparison.CurrentCulture);Console.WriteLine(s.Equals(straße,StringComparison.OrdinalIgnoreCase);/outputsTrue:Console.WriteLine(s.Equals(straße,StringComparison.CurrentCulture);Console.WriteLine(s.Equals(Straße,StringComparison.CurrentCultureIgnoreCase);最安全的实践是总是为E

    11、quals方法提供一个comparisonType的参数。下面是一些基本的指导原则:当比较用户输入的字符串或者将字符串比较结果展示给用户时,使用本地化的比较(CurrentCulture或者CurrentCultureIgnoreCase)。当用于程序设计的比较字符串时,使用原始的比较(Ordinal或者OrdinalIgnoreCase)InvariantCulture和InvariantCultureIgnoreCase一般并不使用,除非在受限的情境之下,因为原始的比较通常效率更高。如果与本地文化相关的比较是必不可少的,它应该被执行成基于当前的文化或者另一种特殊文化的比较。此外,对Equa

    12、ls方法来说,字符串也通常提供了Compare方法,可以提供字符串的相对顺序信息而不仅仅中测试是否相等。这个方法可以很好适用于,和=运算符,对上述讨论同样适用。常见误区 #4: 使用迭代式 (而不是声明式)的语句去操作集合在C# 3.0中,LINQ的引入改变了我们以往对集合对象的查询和修改操作。从这以后,你应该用LINQ去操作集合,而不是通过迭代的方式。一些C#的程序员甚至都不知道LINQ的存在,好在不知道的人正在逐步减少。但是还有些人误以为LINQ只用在数据库查询中,因为LINQ的关键字和SQL语句实在是太像了。虽然数据库的查询操作是LINQ的一个非常典型的应用,但是它同样可以应用于各种可枚

    13、举的集合对象。(如:任何实现了IEnumerable接口的对象)。举例来说,如果你有一个Account类型的数组,不要写成下面这样:decimaltotal=0;foreach(AccountaccountinmyAccounts)if(account.Status=active)total+=account.Balance;你只要这样写:decimaltotal=(fromaccountinmyAccountswhereaccount.Status=active selectaccount.Balance).Sum();虽然这是一个很简单的例子,在有些情况下,一个单一的LINQ语句可以轻易地

    14、替换掉你代码中一个迭代循环(或嵌套循环)里的几十条语句。更少的代码通常意味着产生Bug的机会也会更少地被引入。然而,记住,在性能方面可能要权衡一下。在性能很关键的场景,尤其是你的迭代代码能够对你的集合进行假设时,LINQ做不到,所以一定要在这两种方法之间比较一下性能。#5常见错误:在LINQ语句之中没有考虑底层对象对于处理抽象操纵集合任务,LINQ无疑是庞大的。无论他们是在内存的对象,数据库表,或者XML文档。在如此一个完美世界之中,你不需要知道底层对象。然而在这儿的错误是假设我们生活在一个完美世界之中。事实上,相同的LINQ语句能返回不同的结果,当在精确的相同数据上执行时,如果该数据碰巧在一

    15、个不同的格式之中。例如,请考虑下面的语句:decimaltotal=(fromaccoutinmyaccoutswhereaccout.status=activeselectaccout.Balance).sum();想象一下,该对象之一的账号会发生什么。状态等于“有效的”(注意大写A)?好吧,如果myaccout是Dbset的对象。(默认设置了不同区分大小写的配置),where表达式仍会匹配该元素。然而,如果myaccout是在内存阵列之中,那么它将不匹配,因此将产生不同的总的结果。等一会,在我们之前讨论过的字符串比较中, 我们看见 = 操作符扮演的角色就是简单的比较. 所以,为什么在这个条

    16、件下, = 表现出的是另外的一个形式呢 ?答案是,当在LINQ语句中的基础对象都引用到SQL表中的数据(如与在这个例子中,在实体框架为DbSet的对象的情况下),该语句被转换成一个T-SQL语句。然后遵循的T-SQL的规则,而不是C的规则,所以在上述情况下的比较结束是不区分大小写的。一般情况下,即使LINQ是一个有益的和一致的方式来查询对象的集合,在现实中你还需要知道你的语句是否会被翻译成什么比C的引擎或者是其他表达,来确保您的代码的行为将如预期在运行时。常见错误 #6:对扩展方法感到困惑或者被它的形式欺骗如同先前提到的,LINQ状态依赖于IEnumerable接口的实现对象,比如,下面的简单

    17、函数会合计帐户集合中的帐户余额:publicdecimalSumAccounts(IEnumerablemyAccounts)returnmyAccounts.Sum(a=a.Balance);在上面的代码中,myAccounts参数的类型被声明为IEnumerable,myAccounts引用了一个Sum方法 (C# 使用类似的 “dot notation” 引用方法或者接口中的类),我们期望在IEnumerable接口中定义一个Sum()方法。但是,IEnumerable没有为Sum方法提供任何引用并且只有如下所示的简洁定义:publicinterfaceIEnumerable:IEnum

    18、erableIEnumeratorGetEnumerator();但是Sum方法应该定义到何处?C#是强类型的语言,因此如果Sum方法的引用是无效的,C#编译器会对其报错。我们知道它必须存在,但是应该在哪里呢?此外,LINQ提供的供查询和聚集结果所有方法在哪里定义呢?答案是Sum并不在IEnumerable接口内定义,而是一个定义在System.Linq.Enumerable类中的static方法(叫做“extension method”)namespaceSystem.LinqpublicstaticclassEnumerable./thereferencehereto“thisIEnume

    19、rablesource”is/themagicsaucethatprovidesaccesstotheextensionmethodSumpublicstaticdecimalSum(thisIEnumerablesource,Funcselector);.可是扩展方法和其它静态方法有什么不同之处,是什么确保我们可以在其它类访问它?扩展方法的显著特点是第一个形参前的this修饰符。这就是编译器知道它是一个扩展方法的“奥妙”。它所修饰的参数的类型(这个例子中的IEnumerable)说明这个类或者接口将显得实现了这个方法。(另外需要指出的是,定义扩展方法的IEnumerable接口和Enumer

    20、able类的名字间的相似性没什么奇怪的。这种相似性只是随意的风格选择。)理解了这一点,我们可以看到上面介绍的sumAccounts方法能以下面的方式实现:publicdecimalSumAccounts(IEnumerablemyAccounts)returnEnumerable.Sum(myAccounts,a=a.Balance);事实上我们可能已经这样实现了这个方法,而不是问什么要有扩展方法。扩展方法本身只是C#的一个方便你无需继承、重新编译或者修改原始代码就可以给已存的在类型“添加”方法的方式。扩展方法通过在文件开头添加using namespace;引入到作用域。你需要知道你要找的扩

    21、展方法所在的名字空间。如果你知道你要找的是什么,这点很容易。当C#编译器碰到一个对象的实例调用了一个方法,并且它在这个对象的类中找不到那个方法,它就会尝试在作用域中所有的扩展方法里找一个匹配所要求的类和方法签名的。如果找到了,它就把实例的引用当做第一个参数传给那个扩展方法,然后如果有其它参数的话,再把它们依次传入扩展方法。(如果C#编译器没有在作用域中找到相应的扩展方法,它会抛措。)对C#编译器来说,扩展方法是个“语法糖”,使我们能把代码写得更清晰,更易于维护(多数情况下)。显然,前提是你知道它的用法,否则,它会比较容易让人迷惑,尤其是一开始。应用扩展方法确实有优势,但也会让那些对它不了解或者

    22、认识不正确的开发者头疼,浪费时间。尤其是在看在线示例代码,或者其它已经写好的代码的时候。当这些代码产生编译错误(因为它调用了那些显然没在被调用类型中定义的方法),一般的倾向是考虑代码是否应用于所引用类库的其它版本,甚至是不同的类库。很多时间会被花在找新版本,或者被认为“丢失”的类库上。在扩展方法的名字和类中定义的方法的名字一样,只是在方法签名上有微小差异的时候,甚至那些熟悉扩展方法的开发者也偶尔犯上面的错误。很多时间会被花在寻找“不存在”的拼写错误上。在C#中,用扩展方法变得越来越流行。除了LINQ,在另外两个出自微软现在被广泛使用的类库Unity Application Block和Web

    23、API framework中,也应用了扩展方法,而且还有很多其它的。框架越新,用扩展方法的可能性越大。当然,你也可以写你自己的扩展方法。但是必须意识到虽然扩展方法看上去和其它实例方法一样被调用,但这实际只是幻。事实上,扩展方法不能访问所扩展类的私有和保护成员,所以它不能被当做传统继承的替代品。常见错误#7: 对手头上的任务使用错误的集合类型C#提供了大量的集合类型的对象,下面只列出了其中的一部分:Array,ArrayList,BitArray,BitVector32,Dictionary,HashTable,HybridDictionary,List,NameValueCollection,

    24、OrderedDictionary,Queue, Queue,SortedList,Stack, Stack,StringCollection,StringDictionary.但是在有些情况下,有太多的选择和没有足够的选择一样糟糕,集合类型也是这样。数量众多的选择余地肯定可以保证是你的工作正常运转。但是你最好还是花一些时间提前搜索并了解一下集合类型,以便选择一个最适合你需要的集合类型。这最终会使你的程序性能更好,减少出错的可能。如果有一个集合指定的元素类型(如string或bit)和你正在操作的一样,你最好优先选择使用它。当指定对应的元素类型时,这种集合的效率更高。为了利用好C#中的类型安全

    25、,你最好选择使用一个泛型接口,而不是使用非泛型的借口。泛型接口中的元素类型是你在在声明对象时指定的类型,而非泛型中的元素是object类型。当使用一个非泛型的接口时,C#的编译器不能对你的代码进行类型检查。同样,当你在操作原生类型的集合时,使用非泛型的接口会导致C#对这些类型进行频繁的装箱(boxing)和拆箱(unboxing)操作。和使用指定了合适类型的泛型集合相比,这会带来很明显的性能影响。另一个常见的陷阱是自己去实现一个集合类型。这并不是说永远不要这样做,你可以通过使用或扩展.NET提供的一些被广泛使用的集合类型来节省大量的时间,而不是去重复造轮子。特别是,C#的C5 Generic

    26、Collection Library和CLI提供了很多额外的集合类型,像持久化树形数据结构,基于堆的优先级队列,哈希索引的数组列表,链表等以及更多。常见错误#8:遗漏资源释放CLR 托管环境扮演了垃圾回收器的角色,所以你不需要显式释放已创建对象所占用的内存。事实上,你也不能显式释放。C#中没有与C+delete对应的运算符或者与C语言中free()函数对应的方法。但这并不意味着你可以忽略所有的使用过的对象。许多对象类型封装了许多其它类型的系统资源(例如,磁盘文件,数据连接,网络端口等等)。保持这些资源使用状态会急剧耗尽系统的资源,削弱性能并且最终导致程序出错。尽管所有C#的类中都定义了析构方法

    27、,但是销毁对象(C#中也叫做终结器)可能存在的问题是你不确定它们时候会被调用。他们在未来一个不确定的时间被垃圾回收器调用(一个异步的线程,此举可能引发额外的并发)。试图避免这种由垃圾回收器中GC.Collect()方法所施加的强制限制并非一种好的编程实践,因为可能在垃圾回收线程试图回收适宜回收的对象时,在不可预知的时间内致使线程阻塞。这并意味着最好不要用终结器,显式释放资源并不会导致其中的任何一个后果。当你打开一个文件、网络端口或者数据连接时,当你不再使用这些资源时,你应该尽快的显式释放这些资源。资源泄露几乎在所有的环境中都会引发关注。但是,C#提供了一种健壮的机制使资源的使用变得简单。如果合

    28、理利用,可以大增减少泄露出现的机率。NET framework定义了一个IDisposable接口,仅由一个Dispose()构成。任何实现IDisposable的接口的对象都会在对象生命周期结束调用Dispose()方法。调用结果明确而且决定性的释放占用的资源。如果在一个代码段中创建并释放一个对象,却忘记调用Dispose()方法,这是不可原谅的,因为C#提供了using语句以确保无论代码以什么样的方式退出,Dispose()方法都会被调用(不管是异常,return语句,或者简单的代码段结束)。这个using和之前提到的在文件开头用来引入名字空间的一样。它有另外一个很多C#开发者都没有察觉的

    29、,完全不相关的目的,也就是确保代码退出时,对象的Dispose()方法被调用:using(FileStreammyFile=File.OpenRead(foo.txt)myFile.Read(buffer,0,100);在上面示例中使用using语句,你就可以确定myFile.Dispose()方法会在文件使用完之后被立即调用,不管Read()方法有没有抛异常。常见错误#9: 回避异常C#在运行时也会强制进行类型检查。相对于像C+这样会给错误的类型转换赋一个随机值的语言来说,C#这可以使你更快的找到出错的位置。然而,程序员再一次无视了C#的这一特性。由于C#提供了两种类型检查的方式,一种会抛出异常,而另一种则不会,这很可能会使他们掉进这个“坑”里。有些程序员倾向于回避异常,并且认为不写 try/catch 语句可以节省一些代码。例如,下面演示了C#中进行显示类型转换的两种不同的方式:/方法1:/如果account不能转换成SavingAccount会抛出异常SavingsAccountsavingsAccount=(SavingsAccount)account;/方法2:/如果不能转换,则不会抛出


    注意事项

    本文(C#常见的10个错误及解决方法.docx)为本站会员主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

    copyright@ 2008-2023 冰点文库 网站版权所有

    经营许可证编号:鄂ICP备19020893号-2


    收起
    展开