C#是达成微软公共语言运行库(CLR)的少数语言中的一种。达成CLR的语言可以受益于其带来的特性,如跨语言集成、异常处理、安全性增强、部件组合的简易模型以及调试和分析服务。作为现代的CLR语言,C#是应用最为广泛的,其应用场景针对Windows桌面、移动手机以及服务器环境等复杂、专业的开发项目。
C#是种面向对象的强类型语言。C#在编译和运行时都有的强类型检查,使在大多数典型的编程错误能够被尽早地发现,而且位置定位相当精准。相比于那些不拘泥类型,在违规操作很久后才报出可追踪到莫名其妙错误的语言,这可以为程序员节省很多时间。然而,许多程序员有意或无意地抛弃了这个检测的有点,这导致本文中讨论的一些问题。
本文介绍了10种最常见的编程错误,或是C#程序员要避免的陷阱。
尽管本文中讨论的错误是C#环境下的,但对其他达成CLR或使用框架类库(FCL)的语言也相关(FCL)。
C++以及许多其他语言的程序员习惯于控制他们分配给变量的值是否为简易的值或现有对象的引用。在C#中呢,这将由写该对象的程序员决定,而不是由实例化该对象并对它进行变量赋值的程序员决定。这是新手C#程序员们的共同“问题”。
如果你不知道你正在使用的对象是否是值类型或引用类型,你可能会遇到一些惊喜。例如:
1234567891011 | Point point1 = new Point(20, 30); Point point2 = point1; point2.X = 50; Console.WriteLine(point1.X); // 20 (does this surPRise you?) Console.WriteLine(point2.X); // 50 Pen pen1 = new Pen(Color.Black); Pen pen2 = pen1; pen2.Color = Color.Blue; Console.WriteLine(pen1.Color); // Blue (or does this surprise you?) Console.WriteLine(pen2.Color); // Blue |
如你所见,尽管Point和Pen对象的创建方式相同,但是当一个新的X的坐标值被分配到point2时, point1的值保持不变 。而当一个新的color值被分配到pen2,pen1也随之改变。因此,我们可以推断point1和point2每个都包含自己的Point对象的副本,而pen1和pen2引用了同一个Pen对象 。如果没有这个测试,我们怎么能够知道这个原理?
一种办法是去看一下对象是如何定义的(在Visual Studio中,你可以把光标放在对象的名字上,并按下F12键)
12 |
public struct Point{…} //definesa“value”type
public class Pen{…} //definesa“reference”type |
如上所示,在C#中,struct关键字是用来定义一个值类型,而class关键字是用来定义引用类型的。对于那些有C++编程背景人来说,如果被C++和C#之间某些类似的关键字搞混,可能会对以上这种行为感到很吃惊。
如果你想要依赖的行为会因值类型和引用类型而异,举例来说,如果你想把一个对象作为参数传给一个方法,并在这个方法中修改这个对象的状态。你一定要确保你在处理正确的类型对象。
在C#中,值得类型不能为空。根据定义,值的类型值,甚至初始化变量的值类型必须有一个值。这就是所谓的该类型的默认值。这通常会导致以下,意想不到的结果时,检查一个变量是否未初始化:
123456 |
class Program{
static Pointpoint1; static Penpen1; static void Main( string []args){
Console.WriteLine(pen1== null ); //True
Console.WriteLine(point1== null ); //False(huh?)
}
} |
为什么不是【point 1】空?答案是,点是一个值类型,和默认值点(0,0)一样,没有空值。未能认识到这是一个非常简单和常见的错误,在C#中
很多(但是不是全部)值类型有一个【IsEmpty】属性,你可以看看它等于默认值:
1 | Console.WriteLine(point1.IsEmpty); //True |
当你检查一个变量是否已经初始化,确保你知道值未初始化是变量的类型,将会在默认情况下,不为空值。
在C#中有很多方法来比较字符串。
虽然有不少程序员使用==操作符来比较字符串,但是这种方法实际上是最不推荐使用的。主要原因是由于这种方法没有在代码中显示的指定使用哪种类型去比较字符串。
相反,在C#中判断字符串是否相等最好使用Equals方法:
1 |
public bool Equals( string value); public bool Equals( string value,StringComparisoncomparisonType); |
第一个Equals方法(没有comparisonType这参数)和使用==操作符的结果是一样的,但好处是,它显式的指明了比较类型。它会按顺序逐字节的去比较字符串。在很多情况下,这正是你所期望的比较类型,尤其是当比较一些通过编程设置的字符串,像文件名,环境变量,属性等。在这些情况下,只要按顺序逐字节的比较就可以了。使用不带comparisonType参数的Equals方法进行比较的唯一一点不好的地方在于那些读你程序代码的人可能不知道你的比较类型是什么。
使用带comparisonType的Equals方法去比较字符串,不仅会使你的代码更清晰,还会使你去考虑清楚要用哪种类型去比较字符串。这种方法非常值得你去使用,因为尽管在英语中,按顺序进行的比较和按语言区域进行的比较之间并没有太多的区别,但是在其他的一些语种可能会有很大的不同。如果你忽略了这种可能性,无疑是为你自己在未来的道路上挖了很多“坑”。举例来说:
123456789101112 |
string s= "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( "Straße" ,StringComparison.CurrentCulture));
Console.WriteLine(s.Equals( "straße" ,StringComparison.OrdinalIgnoreCase));
//outputsTrue:
Console.WriteLine(s.Equals( "straße" ,StringComparison.CurrentCulture));
学习交流
热门图片
猜你喜欢的新闻
猜你喜欢的关注
新闻热点 2021-11-16 21:31:39
2021-11-02 13:59:17
2021-11-02 13:52:17
2021-11-01 13:36:51
2021-11-01 13:34:27
2021-11-01 12:56:36
疑难解答 |