我最近正在使用一个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#陷阱分类会很有用。


当前回答

这是另一个让我困惑的问题:

static void PrintHowLong(DateTime a, DateTime b)
{
    TimeSpan span = a - b;
    Console.WriteLine(span.Seconds);        // WRONG!
    Console.WriteLine(span.TotalSeconds);   // RIGHT!
}

时间间隔。Seconds是时间跨度的秒部分(2分钟和0秒的秒值为0)。

时间间隔。TotalSeconds是以秒为单位测量的整个时间跨度(2分钟的总秒值为120)。

其他回答

内存泄漏,因为您没有取消关联事件。

这甚至让我认识的一些高级开发人员被发现了。

想象一个WPF表单,里面有很多东西,你在其中的某个地方订阅了一个事件。如果您不取消订阅,那么关闭和取消引用后,整个表单将保留在内存中。

我相信我看到的问题是在WPF表单中创建一个DispatchTimer并订阅Tick事件,如果你不对计时器做-=,你的表单泄漏内存!

在本例中,您的拆卸代码应该具有

timer.Tick -= TimerTickEventHandler;

这一点特别棘手,因为您在WPF表单中创建了DispatchTimer实例,所以您会认为它是一个由垃圾收集进程处理的内部引用……不幸的是,DispatchTimer在UI线程上使用了一个静态的订阅和服务请求的内部列表,所以引用是由静态类“拥有”的。

可变集合中的值对象

struct Point { ... }
List<Point> mypoints = ...;

mypoints[i].x = 10;

没有效果。

mypoints[i]返回一个Point值对象的副本。c#允许您修改副本的字段。默默地什么也不做。


更新: 这似乎在c# 3.0中被修复了:

Cannot modify the return value of 'System.Collections.Generic.List<Foo>.this[int]' because it is not a variable
enum Seasons
{
    Spring = 1, Summer = 2, Automn = 3, Winter = 4
}

public string HowYouFeelAbout(Seasons season)
{
    switch (season)
    {
        case Seasons.Spring:
            return "Nice.";
        case Seasons.Summer:
            return "Hot.";
        case Seasons.Automn:
            return "Cool.";
        case Seasons.Winter:
            return "Chilly.";
    }
}

错误呢? 不是所有的代码路径都返回一个值… 你在开玩笑吗?我打赌所有代码路径都返回一个值,因为这里提到了每个Seasons成员。它应该已经检查所有enum成员,如果一个成员在开关情况下是缺席的,那么这样的错误将是有意义的,但现在我应该添加一个默认情况下,这是冗余的,永远不会被代码达到。

编辑: 在对这个Gotcha进行了更多的研究之后,我看到了Eric Lippert写得很好的和有用的帖子,但它仍然有点奇怪。你同意吗?

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

LINQ to SQL和一对多关系

这是一个可爱的,咬了我几次,微软把它留给他们自己的开发人员放在她的博客。我不能说得比她更好,来看看。