我最近正在使用一个DateTime对象,并写了这样的东西:

DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?

AddDays()的智能感知文档说它在日期后添加了一天,但它并没有这样做——它实际上返回了一个添加了一天的日期,所以你必须这样写:

DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date

这个问题以前已经困扰过我很多次了,所以我认为将最糟糕的c#陷阱分类会很有用。


当前回答

递归属性有问题

我认为不是c#特有的,而且我确信我在SO的其他地方看到过它(这个问题让我想起了它)

它有两种发生方式,但最终结果是一样的:

忘记引用基数。当重写一个属性时:

 public override bool IsRecursive
 {
     get { return IsRecursive; }
     set { IsRecursive = value; }
 }

从auto-属性改为back -属性,但并没有完全改变:

public bool IsRecursive
{
    get { return IsRecursive; }
    set { IsRecursive = value; }
}

其他回答

抛出收到异常

一个让许多新开发人员困惑的问题是重新抛出异常语义。

我经常看到如下代码

catch(Exception e) 
{
   // Do stuff 
   throw e; 
}

问题是它会清除堆栈跟踪,并使诊断问题变得更加困难,因为您无法跟踪异常起源于何处。

正确的代码是不带参数的throw语句:

catch(Exception)
{
    throw;
}

或者将异常包装在另一个异常中,并使用内部异常获取原始堆栈跟踪:

catch(Exception e) 
{
   // Do stuff 
   throw new MySpecialException(e); 
}

我经常提醒自己DateTime是一个值类型,而不是引用类型。对我来说太奇怪了,特别是考虑到它的各种构造函数。

一些代码:

        List<int> a = new List<int>();
        for (int i = 0; i < 10; i++)
        {
            a.Add(i);
        }

        var q1 = (from aa in a
                  where aa == 2
                  select aa).Single();

        var q2 = (from aa in a
                  where aa == 2
                  select aa).First();

q1 -在这个查询中检查List中的所有整数; Q2 -检查整数,直到找到“正确的”整数。

[Serializable]
class Hello
{
    readonly object accountsLock = new object();
}

//Do stuff to deserialize Hello with BinaryFormatter
//and now... accountsLock == null ;)

这个故事的寓意:反序列化对象时不运行字段初始化程序

垃圾收集和Dispose()。虽然不需要做任何事情来释放内存,但仍然需要通过Dispose()释放资源。当你使用WinForms或以任何方式跟踪对象时,这是一个非常容易忘记的事情。