VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之C#开发人员应该知道的13件事情(2)

使用volatile

将字段标记为“易变”是高级功能,即使专家也经常误解。C#编译器将确保访问字段具有获取和释放语义; 这不同于确保对该字段的所有访问都处于锁定状态。如果你不知道什么是获取和释放语义,以及它们如何影响CPU级优化,则应避免使用volatile字段。相反,应该使用较高级别的工具,如任务并行库或CancellationToken类型。

利用线程安全的内置方法

标准库类型通常提供方便线程安全访问对象的方法。例如,Dictionary.TryGetValue()。使用这些方法通常使你的代码更清洁,你不需要担心如TOCTTOU or TOCTOU场景等数据竞争的情况。

不要锁定“this”,字符串或其他常见的公共对象

当实现在多线程上下文中使用的类时,要非常小心使用锁。锁定此字符串或其他公共对象,会阻止封装锁定状态,并可能导致死锁。你需要防止其他代码锁定你的实现上正在使用的对象; 最安全的做法是使用一个私人的对象成员。

 

13. 避免常见错误

引用null

不适当的使用null,是编码缺陷的常见来源,可能会导致程序崩溃和其它意外行为。如果你尝试访问一个空引用,以为它是一个对象的有效引用一样 - 例如,通过访问一个属性或方法,运行时将抛出一NullReferenceException异常。

静态和动态分析工具可以帮助你在发布代码之前识别潜在的NullReferenceException异常。在C#中,空引用通常由尚未引用对象的变量引起。对于空值类型和引用类型来说,Null是一个有效值。例如,Nullable <Int>,空委托,取消订阅事件,会在“as”转换,以及在许多其他情况下失败。

每个空引用异常是都一个错误。不应该去捕获NullReferenceException,而应该尝试在使用它们之前测试对象是否为null。这也使得代码更容易被最小化try / catch块读取。

从数据库表中读取数据时,请确保,缺失值可以表示为DBNull对象,而不是空引用。不要指望它们表现的像潜在的空引用。

将十进制值替换为二进制数

浮点数和双精度表示二进制有理数,不是小数有理数,在存储十进制值时必须使用二进制的近似值。从十进制的角度来看,这些二进制近似具有不一致的舍入和精度 - 有时导致算术运算的意外结果。因为浮点运算通常在硬件中执行,硬件条件可能会不可预测地加剧这些差异。

当小数精度非常重要时,使用十进制,就像财务计算等情况。

修改结构

一个常见的错误情况是忘记结构体是值类型的,这就意味着它们被复制了并且通过值来进行传递。假设你有这样的代码:

复制代码
struct P { public int x; public int y; }
void M()
{
   P p = whatever;
   …
   p.x = something;
   …
   N(p);
复制代码

有一天,维护者决定将代码重构为:

复制代码
void M()
{
   P p = whatever;
   Helper(p);
   N(p);
}
void Helper(P p)
{ 
   …
   p.x = something;
复制代码

现在当在M()中调用N(p)时,p具有错误的值。调用助手(p)传递p的副本,而不是p的引用,因此Helper()中执行的变化将丢失。相反,Helper会返回修改的p的副本。

意外的算术

C#编译器保护你出现常量的算术溢出,但不一定是计算值。

忽略保存返回值

与结构体不同,类是引用类型,方法可以修改引用的对象。然而,不是所有的对象方法都实际修改了引用的对象,一些会返回一个新对象。当开发人员调用后者时,他们需要记住将返回值赋给变量,以便使用修改后的对象。在代码审查期间,这种类型的问题通常在会被发现。一些对象,如字符串,是不可变的,所以方法从不修改这些对象。即使如此,开发人员也会通常忘记。

例如,考虑string.Replace():

string label = “My name is Aloysius”;
label.Replace(“Aloysius”, “secret”);

 代码打印“我的名称是Aloysius”,因为Replace方法不修改字符串。

不要使迭代器/枚举器变得无效

不要在迭代时修改集合。

复制代码
List<Int> myItems = new List<Int>{20,25,9,14,50};
foreach(int item in myItems)
{
    if (item < 10)
    {
        myItems.Remove(item);
        // iterator is now invalid!
        // you’ll get an exception on the next iteration
复制代码

如果你运行这个代码,一旦循环到集合中的下一个项目时。你会收到一个异常抛出。

正确的解决方案,是使用第二个列表来保存你要删除的项目,然后在删除时迭代该列表:

复制代码
List<Int> myItems = new List<Int>{20,25,9,14,50};
List<Int> toRemove = new List<Int>();
foreach(int item in myItems)
{
   if (item < 10)
   {
        toRemove.Add(item);         
   }
}
foreach(int item in toRemove)
{
复制代码

或者如果你使用C#3.0或更高版本,你可以使用List <T> .RemoveAll。

就像这样:

myInts.RemoveAll(item => (item < 10));

属性名称错误

在实现属性时,请注意属性名称不同于类中使用的数据成员。在访问属性时,容易意外使用相同的名称,并导致出现无限递归的情况。

复制代码
// The following code will trigger infinite recursion
private string name;
public string Name
{
    get
    {
        return Name;  // should reference “name” instead.
复制代码

当重命名间接属性时要小心。例如,WPF中的数据绑定,会将属性名称指定为字符串。如果不小心更改该属性名称,你将会无意中创建了一个编译器无法防护的问题。

以上就是所有C#开发人员应该知道的13件事情。

了解了C#开发中应该知道的13件事情,有助于我们更好地使用C#进行开发,当然在开发时,也可以借助一些使用C#编写的开发工具。如ComponentOne Studio Enterprise,这是一款专注于企业应用的.NET全功能控件套包,支持WinForms、WPF、UWP、ASP.NET MVC等多个平台,帮助、在缩减成本的同时,提前交付丰富的桌面、Web和移动企业应用。

 

相关阅读:

是什么让C#成为最值得学习的编程语言

从Visual Studio看微软20年技术变迁

Visual Studio 2017正式版发布全纪录

 


相关教程