C#几个经常犯错误汇总
在我们平常编程中,时间久了有时候会形成一种习惯性的思维方式,形成固有的编程风格,但是有些地方是需要斟酌的,即使是一个很小的错误也可能会导致昂贵的代价,要学会善于总结,从错误中汲取教训,尽量不再犯同样错误,注重编程之美,代码的优雅,总结几个平常经常犯的错误。
1、在C#编程中,字符型类型是最容易处理出错的地方,代价是非常昂贵,在.Net Framwork中,字符串是一个相当特别的引用类型,string本省就是一个不可继承的密封类,但是它具有了值类型所应用的特点,但是它在CLR中内 存还是保存于托管堆之上,也就是说,当我们每次定义一个字符串类型的时候,就在堆内存中开辟一端内存,而当我们字符串被修改之后,它会创建一个新的内存, 注意这里的内存是不连续的,而是通过修改栈内地址引用而拼凑字符串,不会改变源字符串在内存中的地址,所以有些程序员总是喜欢使用这样的方法格式化字符 串:
- string SelectText="select * from "+TableName+" where UserName='"+Name+"'";
上述代码,使用了字符串拼凑的方法,因为使用了多重串联,因此会在内存中创建两个不必要的字符串垃圾副本。
其实在C#中,已经为我们提供了StringBuilder和String.Fromat来解决此问题,虽然他们可以实现同样的功能,但是他们有质 的变化,StringBuilder在内存中开辟的是一段连续内存,当增加新字符串时候,它会在栈中指向的同一个堆内存中连续存放字符,这就形成了性能的 提升。所以我们将上面代码改成:
- string SelectText=string.Format("select * from {0} where UserName={1}",TableName,Name);
2、大多数开发人员都不知道内置的验证数据类型的方法,如System.Int32,因此很多人都是自己实现的,其实这是不妥的,因为这些基本类型中都存在自己固有的类型验证方法,下面这个就是自己实现验证的一个字符串是否是数值的代码:
- public bool CheckIfNumeric(string value)
- {
- bool IsNumeric=true;
- try
- {
- int i=Convert.ToInt32(value);
- }
- catch(FormatException excepiton)
- {
- IsNumeric=false;
- }
- return IsNumeric;
- }
虽然使用了try catch语句,这不是最佳的做法,更好的方法是下面使用Int.TryParse;
- int output=0;
- bool IsNumeric=int.TryParse(value,out output);
int.TryParse是更快、更简洁的方法。
3、自己利用IDisposable接口手动释放内存
在.NET Framework中,对象的处理和使用一样重要,理想的方法是在使用完对象的时候,在类中实现IDisposable接口中的dispose方法进行内 存的释放,当然在.Net本身提供的垃圾回收机制(GC)中就提供了这样的功能,在我们实例化类对象时,在类本身的析构函数中会调用dispose方 法,GC在各级内存堆满的情况下,自动检查对象使用情况,去相应的释放内存,但是运行在非托管平台上的方法,需要我们自己手动释放内存,比如我们常见的 SqlConnection对象,也就有了下面的创建、使用和处理方法:
- public void DALOneMethod()
- {
- SqlConnection connection=null;
- try
- {
- connection =new SqlConnection("。。。。。。。。。。。");
- connection.Open();
- //sqlcommand。。run
- }
- catch(Exception exception)
- {
- // manager exception
- }
- finally
- {
- connection.Close();
- connection.Disopse();
- }
- }
上述代码是大部分程序员会出现的代码,乍看没啥问题,连接处理在最后一个代码中被明确调用,但是如果发生了一个异常,catch代码块就被执行,然 后再执行最后一个代码块处理连接,因此在最后一个代码块执行之前,连接将一直留在内存中,大部分我们会在此处记录错误,一般涉及到IO操作,如果延时时间 比较长的话,这个连接将在内存时间长时间停留。我们一个原则就是当对象不再使用的时候我们里面释放资源。
我们采用程序逻辑域来处理这个问题会更好:
- public void DALOneMethod()
- {
- using(SqlConnction connection=new SqlConnection("。。。。。。。"))
- {
- connction.Open();
- // do SUAD
- }
- }
当使用using代码快时,对象上的dispose()方法将在执行推出逻辑域的时候调用,这样就保证了SqlConnection的资源处理被尽 早释放,当然这个方法也适用于实现IDisposable接口的类,当时个人不推荐这样做,在非常有把握的情况下可以手动释放,但是没把握还是叫 给.net系统释放,因为本身类的析构函数就实现这个方法,当我们自己重写后,反而会导致系统误以为你自己定义了方法,而推迟释放资源,有兴趣可以研究下 GC运行本质,假如能在第一代被释放的内存,如果我们重写dispose方法反而推迟到第二代内存堆中释放,显然是不可取的。
4、学会合理的管理公共变量,我们在系统中经常会滥用公共变量,没有做到合适的封装好。
- static void Main(string[] args)
- {
- MyAccount account=new MyAccount();
- //这地方不能随便的调用account里面的字段进行更改,但是缺改了
- account.AccountNumber="ddddddddd";
- Console.ReadKey();
- }
- public class MyAccount
- {
- public string AccountNumber;
- public MyAcctount()
- {
- AccountNumber="ssssssssssssss";
- }
- }
在上面的MyAccount类中生命了一个AccountNumber公共变量,理想情况下,AccountNumber应该是只读的,不能让外界修改,但是这里MyAccount类却没有对它做任何控制。
声明公共做法应该是使用属性,如:
- public class MyAccount
- {
- private stirng _accountNumber;
- public string AccountNumber
- {
- get { return _accountNumber; }
- }
- public MyAccount()
- {
- _accountNumber="dddddddd";
- }
- }
这里我们封装了AccountNumber公共变量,它变成了只读,不能由调用者类进行修改。
5、嵌套的异常处理,有的开发人员喜欢在方法末尾加上处理的嵌套方法,如
- public class NestedExceptionHandling
- {
- public void MainMethod()
- {
- try
- {
- //some implementation
- ChildMethod1();
- }
- catch (Exception exception)
- {
- //Handle exception
- }
- }
- private void ChildMethod1()
- {
- try
- {
- //some implementation
- ChildMethod2();
- }
- catch (Exception exception)
- {
- //Handle exception
- throw;
- }
- }
- private void ChildMethod2()
- {
- try
- {
- //some implementation
- }
- catch (Exception exception)
- {
- //Handle exception
- throw;
- }
- }
- }
如果相同的异常被处理多次,性能开销将会增加。
我们的解决方法是让异常处理方法独立开来,如:
- public class NestedExceptionHandling
- {
- public void MainMethod()
- {
- try
- {
- //some implementation
- ChildMethod1();
- }
- catch(Exception exception)
- {
- //Handle exception
- }
- }
- private void ChildMethod1()
- {
- //some implementation
- ChildMethod2();
- }
- private void ChildMethod2()
- {
- //some implementation
- }
- }
6、大数据量上使用Dataset和DataReader混用,当单表数据量很大的情况,使用DataSet是一种很不明智的选择,应为 DataSet是以DataTable内存形式存放数据量,一次性将数据拖入内存,当数据很大的情况下,这种方式是很吃内存的,相比 DataSer,DataReader就显得优雅很多,它是每次读取一条数据,然后轮询调用机制,但是也有它的弊端,就是相对长连接,但是对内存消耗而言 这是有利的,当然DataSet在大部分应用场景下也是有自己的优点,充分解耦、一次性操作、领域模型操作等方面,两者分情况分场景而用,这里只是稍微提 提,根据场景分析区别。
原文链接:http://www.cnblogs.com/zhijianliutang/archive/2012/03/20/2407688.html
C#几个经常犯错误汇总的更多相关文章
- 编程中易犯错误汇总:一个综合案例.md
# 11编程中易犯错误汇总:一个综合案例 在上一篇文章中,我们学习了如何区分好的代码与坏的代码,如何写好代码.所谓光说不练假把式,在这篇文章中,我们就做一件事——一起来写代码.首先,我会先列出问题,然 ...
- Entity Framework学习笔记——错误汇总
之前的小项目做完了,到了总结经验和更新学习笔记的时间了.开始正题之前先啰嗦一下,对之前的学习目标进行一个调整:“根据代码生成表”与“生成数据库脚本和变更脚本”合并为“Code First模式日常使用篇 ...
- 李洪强iOS开发之OC常见错误汇总
// // main.m // 16 - 常见错误汇总 // // Created by vic fan on 16/7/13. // Copyright © 2016年 李洪强. All r ...
- scanf()常犯错误
------------------------------------------------------------------------ <> 本意:接收字符串. 写成代码:voi ...
- Python常见的错误汇总
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 错误: [错误分析]第二个参数必须为类,否则会报TypeError,所以正确的应 ...
- PHP常见错误汇总
日常开发和调试的时候,经常会遇到一些错误,光怪陆离的不知所以,所以,特此将错误汇总一下,借鉴!!! 1. 原因分析: 一般可能是该文件出现了问题,检查一下代码和格式,是否出现开始的地方出现了空格,或 ...
- Quartus II 中 Verilog 常见警告/错误汇总
Verilog 常见错误汇总 1.Found clock-sensitive change during active clock edge at time <time> on regis ...
- [golang 易犯错误] golang 局部变量初始化:=的陷阱
我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋 ...
- Python 新手常犯错误
Python 新手常犯错误(第二部分) 转发自:http://blog.jobbole.com/43826/ 作用域 在这篇文章里,我们来关注作用域在Python被误用的地方.通常,当我们定义了一个全 ...
随机推荐
- dll开发中遇到的问题
刚碰到个问题,我的一个项目中引用了一个dll,这个dll又引用了另一个dll,我把这俩个都放在bin文件夹下,但是会报错,说第二个dll找不到.把它放到系统文件夹system32下就没事了. 但是遇到 ...
- 在线教育服务:http://www.ablesky.com/
在线教育服务:http://www.ablesky.com/
- poj3041
Asteroids Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12162 Accepted: 6620 Descri ...
- MyGeneration模板生成NHibernate映射文件和关系(one-to-one,one-to-many,many-to-many)
MyGeneration的几个NHibernate模板功能已经很强,但还是存在些问题.例如:Guid主键支持不佳,代码不易修改,不支持中文注释等等.所以我决定自己来改写此模版.我把一部分通用的函数提取 ...
- phper 要求
做了这么多年php,今天看到一个07年的老文,才发现自己的水平太菜.转过来激励下自己 说句实话,写这个真够无聊的.本来看了某位大虾的类似文章,腹诽了几句也就算了.但是昨天晚上有个客户拿着这篇文章问我: ...
- Linux下C程序的编辑,编译和运行以及调试
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- WIM更新命令(打补丁)
在D盘新建3个文件夹:win7(install.wim).updates(补丁).win7ultra 1.先打开ISO文件,然后加载映像到D:\win7ultra文件夹dism /mount-wim ...
- Codeforces Gym 100002 D"Decoding Task" 数学
Problem D"Decoding Task" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com ...
- delphi 取得汉字的第一个字母
功能说明://取得汉字的第一个字母 function GetPYIndexChar( hzchar:string):char;begin caseWORD(hzchar[1])shl8+WORD(h ...
- [Codeforces] 347B - Fixed Points
题意:给定一个序列,现有一种操作:两个数的位置互换.问最多操作一次.序列 [元素位置i] 与 [元素Ai] 相等的最多个数? 依据题意,最多个数为 : [操作之前[元素位置i] 与 [元素Ai] ...