看似简单!解读C#程序员最易犯的7大错误

  编程时犯错是必然的,即使是一个很小的错误也可能会导致昂贵的代价,聪明的人善于从错误中汲取教训,尽量不再重复犯错,在这篇文章中,我将重点介绍C#开发人员最容易犯的7个错误。

  格式化字符串

  在C#编程中,字符串类型是最容易处理出错的地方,其代价往往也很昂贵,在.NET Framework中,字符串是一个不可变的类型,当一个字符串被修改后,总是创建一个新的副本,不会改变源字符串,大多数开发人员总是喜欢使用下面这样的方法格式化字符串:

string updateQueryText = "UPDATE EmployeeTable SET Name='" + name

+ "' WHERE EmpId=" + id;

  上面的代码太乱了,由于字符串是不可变的,这里它又使用了多重串联,因此会在内存中创建三个不必要的字符串垃圾副本。

  最好的办法是使用string.Format,因为它内部使用的是可变的StringBuilder,也为净化代码铺平了道路。

string updateQueryText = string.Format("UPDATE EmployeeTable SET Name='{0}'

WHERE EmpId={1}", name, id);

  •   嵌套异常处理

  开发人员喜欢在方法的末尾加上异常处理的嵌套方法,如:

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

}

}

  •   在大型数据集上使用foreach

  大部分开发人员更喜欢使用foreach循环,而无视for循环,因为foreach更容易使用,但操作大型数据集时,使用foreach已经被证明是代价高昂的,在下面的代码中,我同时使用for和foreach遍历相同的数据库,在图1中显示了两种循环方法消耗的时间。

static void Main(string[] args)

{

DataTable dt = PopulateData();

Stopwatch watch = new Stopwatch();

//For loop

watch.Start();

for (int count = 0; count < dt.Rows.Count; count++)

{

dt.Rows[count]["Name"] = "Modified in For";

}

watch.Stop();

Console.WriteLine("Time taken in For loop: {0}",watch.Elapsed.TotalSeconds);

//Foreach loop

watch.Start();

foreach (DataRow row in dt.Rows)

{

row["Name"] = "Modified in ForEach";

}

watch.Stop();

Console.WriteLine("Time taken in For Each loop: {0}",watch.Elapsed.TotalSeconds);

Console.ReadKey();

}

  图 1 for和foreach循环遍历相同数据库消耗的时间对比
  从上图可以看出,foreach循环明显要慢一些,它消耗的时间几乎是for循环的两倍,这是因为foreach循环中的dt.Rows要访问数据库中的所有行。因此需要遍历大型数据集时最好使用for循环。

  验证简单的原始数据类型

  大多数开发人员都不知道内置的验证原始数据类型的方法,如System.Int32,因此很多人都是自己实现的,下面就是一个自己实现的验证一个字符串是否是数值的代码:

public bool CheckIfNumeric(string value)

{

bool isNumeric = true;

try

{

int i = Convert.ToInt32(value);

}

catch(FormatException exception)

{

isNumeric = false;

}

return isNumeric;

}

  它使用了try catch语句,因此不是最佳的做法,更好的办法是象下面这样使用int.TryParse:

int output = 0;

bool isNumeric = int.TryParse(value, out output);

  根据我的经验,int.TryParse是更快,更简洁的方法。  

  处理对象实现IDisposable接口

  在.NET Framework中,对象的处理和使用一样重要,理想的办法是在类中实现IDisposable接口的dispose方法,在使用这个类的对象后,可以通过调用dispose方法进行处理。

  下面的代码显示了一个SqlConnection对象的创建,使用和处理:

public void DALMethod()

{

SqlConnection connection = null;

try

{

connection = new SqlConnection("XXXXXXXXXX");

connection.Open();

//implement the data access

}

catch (Exception exception)

{

//handle exception

}

finally

{

connection.Close();

connection.Dispose();

}

}

  在上面的方法中,连接处理在最后一个代码块中被明确调用,如果发生一个异常,catch代码块就会执行,然后再执行最后一个代码块处理连接,因此在最后一个代码块执行之前,连接将一直留在内存中,.NET Framework的一个基本原则就是当对象不被使用时就应该释放资源。

  下面是调用dispose更好的办法:

public void DALMethod()

{

using (SqlConnection connection = new SqlConnection("XXXXXXXXXX"))

{

connection.Open();

//implement the data access

}

}

  当你使用using代码块时,对象上的dispose方法将在执行退出代码块时调用,这样可以保证SqlConnection的资源被处理和尽早释放,你也应该注意到这个办法也适用于实现IDisposable接口的类。

  声明公共变量

  听起来可能有点简单,但我们经常看到滥用公共变量声明的情况,先来看一个例子:

static void Main(string[] args)

{

MyAccount account = new MyAccount();

//The caller is able to set the value which is unexpected

account.AccountNumber = "YYYYYYYYYYYYYY";

Console.ReadKey();

}

public class MyAccount

{

public string AccountNumber;

public MyAccount()

{

AccountNumber = "XXXXXXXXXXXXX";

}

}

  在上面的MyAccount类中声明了一个AccountNumber公共变量,理想情况下,AccountNumber应该是只读的,但MyAccount类却没有对它实施任何控制。

  声明公共变量正确的做法应该是使用属性,如:

public class MyAccount

{

private string _accountNumber;

public string AccountNumber

{

get { return _accountNumber; }

}

public MyAccount()

{

_accountNumber = "XXXXXXXXXXXXX";

}

}

  这里MyAccount类对AccountNumber公共变量实施了很好的控制,它变成只读,不能由调用者类修改。

  利用System.Data.DataTable访问数据

  我常常看到开发人员使用列索引从数据库访问数据,如:

public class MyClass

{

public void MyMethod()

{

//GetData fetches data from the database using a SQL query

DataTable dt = DataAccess.GetData();

foreach (DataRow row in dt.Rows)

{

//Accessing data through column index

int empId = Convert.ToInt32(row[0]);

}

}

}

  按照这种写法,如果列顺序在SQL查询匹配数据时发生了变化,你的应用程序将会受到影响,正确的做法应该是使用列名访问数据。

public class MyClass

{

private const string COL_EMP_ID = "EmpId";

public void MyMethod()

{

//GetData fetches data from the database using a SQL query

DataTable dt = DataAccess.GetData();

foreach (DataRow row in dt.Rows)

{

//Accessing data through column name

int empId = Convert.ToInt32(row[COL_EMP_ID]);

}

}

}

  这样的代码更加稳固,列顺序发生变化不会给应用程序造成任何影响,如果在一个地方使用局部变量保存列名更好,即使将来你的列名发生了变化,也不用修改应用程序代码。

  小结

  我希望你能从自身和其他程序员所犯的错误中汲取教训,避免犯同样的错误,如果你对本文阐述的C#程序员常犯的7类错误持有不同的看法,欢迎发表你的意见和想法。

时间: 2023-01-14

看似简单!解读C#程序员最易犯的7大错误的相关文章

一起谈.NET技术,看似简单!解读C#程序员最易犯的7大错误

编程时犯错是必然的,即使是一个很小的错误也可能会导致昂贵的代价,聪明的人善于从错误中汲取教训,尽量不再重复犯错,在这篇文章中,我将重点介绍C#开发人员最容易犯的7个错误. 格式化字符串 在C#编程中,字符串类型是最容易处理出错的地方,其代价往往也很昂贵,在.NET Framework中,字符串是一个不可变的类型,当一个字符串被修改后,总是创建一个新的副本,不会改变源字符串,大多数开发人员总是喜欢使用下面这样的方法格式化字符串: string updateQueryText = "UPDATE E

安全应急响应工作中易犯的5大错误

本文讲的是 安全应急响应工作中易犯的5大错误,转行或开启一份新工作的最大挑战之一,不是了解该做什么,而是学会不能做什么. 人非圣贤,孰能无过?但在安全行业,小过失往往造成大损失.下面是安全响应中一些常见的错误,以及安全专家给出的真知灼见. 无准备 对没准备的公司,发现自己被攻击的事实可能会带来恐慌.无效响应和难以承受的账单.你知道攻击事件中得弄清哪些问题,不妨设置好整体计划以应对这些问题,有备无患. 比如说:哪些数据被盗了?攻击者是怎么进到公司网络的?他们在公司网络中畅游多久了?都有哪些系统被他

PHP程序员最易犯10种错误

PHP是个伟大的web开发语言,灵活的语言,但是看到php程序员周而复始的犯的一些错误.我做了下面这个列表,列出了PHP程序员经常犯的10中错误,大多数和安全相关.看看你犯了几种 1.不转意html entities   一个基本的常识:所有不可信任的输入(特别是用户从form中提交的数据) ,输出之前都要转意. echo $_GET[''usename''] ; 这个例子有可能输出: <scrīpt>/*更改admin密码的脚本或设置cookie的脚本*/</scrīpt> 这是

PHP程序员最易犯10种错误总结,phper的你中几枪?

1.不转意html entities 一个基本的常识:所有不可信任的输入(特别是用户从form中提交的数据) ,输出之前都要转意. echo $_GET['usename'] ; 这个例子有可能输出: <script>/*更改admin密码的脚本或设置cookie的脚本*/</script> 这是一个明显的安全隐患,除非你保证你的用户都正确的输入. 如何修复 : 我们需要将"< ",">","and" 等转换成

你与其他程序员可能常犯的 6 个错误

我担任 CTO 已经有一段时间了,我觉得这是一个非常好的锻炼机会,因为我不仅可以编写代码,还要带领团队,管理项目,设计架构,组织工作,审查代码,调查不同的问题,研究各种解决方案,了解许多技术以及联系客户等等. 通过这么广泛的任务,我学到了很多不同的技能,并有很多想法想跟大家分享一下.也许你的观点是不同的,也许你学到了一些其他的东西想在这里跟我们分享一下.我期待着听到您的意见和见解. 本文主要针对 CTOs 和程序员,因为不是每个人都遇到过这些我观察到的.学到的和解决过的问题. 问题1. "我对X

数据挖掘中易犯的11大错误

按照Elder博士的总结,这10大易犯错误包括: 0. 缺乏数据(Lack Data) 1. 太关注训练(Focus on Training) 2. 只依赖一项技术(Rely on One Technique) 3. 提错了问题(Ask the Wrong Question) 4. 只靠数据来说话(Listen (only) to the Data) 5. 使用了未来的信息(Accept Leaks from the Future) 6. 抛弃了不该忽略的案例(Discount Pesky Ca

必看 :大数据挖掘中易犯的11大错误

0.缺乏数据(LackData) 对于分类问题或预估问题来说,常常缺乏准确标注的案例. 例如: 欺诈侦测(FraudDetection):在上百万的交易中,可能只有屈指可数的欺诈交易,还有很多的欺诈交易没有被正确标注出来,这就需要在建模前花费大量人力来修正. 信用评分(CreditScoring):需要对潜在的高风险客户进行长期跟踪(比如两年),从而积累足够的评分样本. 1.太关注训练(FocusonTraining) IDMer:就象体育训练中越来越注重实战训练,因为单纯的封闭式训练常常会训练

看似简单,思考了很久的编程题,大神求解???

问题描述 看似简单,思考了很久的编程题,大神求解??? 输入n(1-10之间数字),将数字分解显示,如6可以显示为6,5+1,4+2,4+1+1..... 解决方案 http://ideone.com/bhnyWO 1+1+1+1+1 1+1+1+2 1+1+3 1+2+2 1+4 2+3 5 解决方案二: using System; using System.Linq; using System.Collections.Generic; public class Test { static i

java-最简单的struts2程序,总是提示404,求大神指点

问题描述 最简单的struts2程序,总是提示404,求大神指点 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd&qu