-
C#教程之C#新手常犯的错误汇总
本文所述为C#新手常犯的错误,但是实际上很多有经验的程序员也经常犯这些错误,对此特别整理了一下,供大家参考。具体如下:
1、遍历List的错误,比如如下代码:
1
2
3
4
5
|
List<String> strList =newList<String> for ( int i =0; i<strList.Count; i++) { strList.RemoveAt(i); } |
这段代码看上去是删除了所有元素,实际上每次调用RemoveAt方法会导致List元素索引重排,最后导致元素没有完全删除。
可以改成:
1
2
3
4
5
6
|
List<String> strList =newList<String> for ( int i =0; i<strList.Count; i++) { strList.RemoveAt(i); i-=1; } |
这样就可以完全删除List中的元素。
2、关于C#常量的错误
比如你写了一个类库,在里面定义了如下常量:
1
|
public const String str= "First Version" ; |
并且在另一个程序里引用了这个类库,如果你修改了这个类库中的常量,发布了一个新的版本,那么再运行之前的程序,你会发现常量还是原来的常量,并没有改变。这是因为C#在编译的时候,常量直接作为元数据嵌入,解决方法是重新编译整个解决方案或者使用属性而不是直接访问常量。
3、当把值类型装箱后,如果拆箱只能拆成原来装箱前的类型,比如:
1
2
3
4
5
6
|
Int32 a=3; Object obj= new object (); //这里装箱成功,不会失败 obj=i; //拆箱一定会失败 Int64 b=(Int64)obj; |
可以像这样操作:
1
|
Int64 b =(Int64)(Int32)obj; |
就能完成转型
4、重载==运算符的错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace UseOperator { class Program { static void Main( string [] args) { Test t1 = new Test(); t1.MyFun(); Console.ReadLine(); } } class Test { public void MyFun() { Test t = new Test(); if (t == null ) { Console.WriteLine( "t为空!" ); } else { Console.WriteLine( "t不为空!" ); } } //存在BUG的重载运算法 public static bool operator ==(Test t1, Test t2) { return t2.Equals(t1); } public static bool operator !=(Test t1, Test t2) { return !(t1 == t2); } //覆盖HashCode public override int GetHashCode() { return base .GetHashCode(); } public override bool Equals( object obj) { return base .Equals(obj); } } } |
这里的问题在于MyFun中会把NULL传递进==运算符函数,导致运行的时候报错,正确的做法是:
1
2
3
4
5
6
7
8
9
10
11
|
public static bool operator ==(Test t1, Test t2) { if ((t2 as object ) == null ) { return (t1 as object ) == null ; } else { return t2.Equals(t1); } } |
5、C#中调用结构的属性或者方法必须用new来声明结构变量,否则会出错。
6、如果使用了params使用多个参数,必须判断参数是否为空,否则程序会有隐藏的BUG。
7、静态成员在创建第一个实例的时候就会初始化,而且只被初始化一次,不要乱用静态成员。
8、如果使用ref Object类型参数接受String类型会出错,这是因为C#要求参数必须使用正确的类型,不加ref是可以的,如果一定要使用ref Object接受String类型参数,可以先转型成Object,再引用传递。
9、类的构造函数中永远不要调用虚方法,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace FransferVirtualFunction { class Program { static void Main( string [] args) { try { Child ch = new Child(); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } } public class Ref { public string Str = "这是Ref类的一个成员" ; } public class Parent { protected Ref my; public Parent() { my = new Ref(); //构造方法中调用了虚方法 Console.WriteLine(GetString()); } //虚方法 public virtual string GetString() { return my.Str; //使用了内部成员 } } public class Child : Parent { private Ref my2; public Child() : base () { my2 = new Ref(); } //重写虚方法 public override string GetString() { return my2.Str; //使用了内部成员 } } } |
这里在执行基类的构造函数的时候会执行到派生类的虚方法GetString(),在获取my2.Str的时候抛出异常,因为此时派生类对象还没有被构造。
10、在C#和SQL Server通信时要注意NULL的含义,在SQL Server里面这个值代表1900-1-1。SQL Server的空值可以使用DBNull来表示。
暂时就是这么多了,注意到以上10点可以在编程的时候减少大量BUG。
补充:
1、Math 三角函数 其中的参数为 弧度值,而非角度值。
2、WinForm 中的由相对路径引发的bug:具体可以参考WinForm相对路径的陷阱。
3、使用 xml, json 等序列化后的数据格式传递数据时,如果传递的数据为数值型类型,解析时,最好先将其转为string 然后 tryParse 成相应类型。
至于原因:如上的第三点、是装箱和拆箱的问题。
相信本文所述对大家C#程序设计可以带来很大的帮助。