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


当前回答

private int myVar;
public int MyVar
{
    get { return MyVar; }
}

心想。你的应用在没有堆栈跟踪的情况下崩溃了。这种事经常发生。

(请注意getter中的大写MyVar而不是小写MyVar。)

其他回答

Dictionary<,>: "返回项的顺序未定义"。这很可怕,因为它有时会咬你一口,但会对其他人起作用,如果你只是盲目地认为Dictionary会表现得很好(“为什么不呢?”我想,是List做的”),在你最终开始质疑你的假设之前,你真的必须深入了解它。

(这里也有类似问题。)

如果你正在为MOSS编写代码,你以这种方式获得一个站点引用:

SPSite oSiteCollection = SPContext.Current.Site;

之后在你的代码中你说:

oSiteCollection.Dispose();

从MSDN:

If you create an SPSite object, you can use the Dispose method to close the object. However, if you have a reference to a shared resource, such as when the object is provided by the GetContextSite method or Site property (for example, SPContext.Current.Site), do not use the Dispose method to close the object, but instead allow Windows SharePoint Services or your portal application to manage the object. For more information about object disposal, see Best Practices: Using Disposable Windows SharePoint Services Objects.

每个MOSS程序员都会遇到这种情况。

TextInfo textInfo = Thread.CurrentThread.CurrentCulture.TextInfo;

textInfo.ToTitleCase("hello world!"); //Returns "Hello World!"
textInfo.ToTitleCase("hElLo WoRld!"); //Returns "Hello World!"
textInfo.ToTitleCase("Hello World!"); //Returns "Hello World!"
textInfo.ToTitleCase("HELLO WORLD!"); //Returns "HELLO WORLD!"

是的,这种行为是有记录的,但这并不能证明它是正确的。

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

合同在流。阅读是我见过很多人被绊倒的东西:

// Read 8 bytes and turn them into a ulong
byte[] data = new byte[8];
stream.Read(data, 0, 8); // <-- WRONG!
ulong data = BitConverter.ToUInt64(data);

这是错误的原因是流。Read最多读取指定的字节数,但完全可以只读取1个字节,即使在流结束前还有7个字节可用。

它看起来与Stream如此相似,这并没有什么帮助。如果没有异常返回,则保证已写入所有字节。上面的代码几乎一直都能工作,这也没有什么帮助。当然,没有现成的、方便的方法来正确地读取N个字节也无济于事。

所以,为了堵住这个漏洞,提高人们的意识,这里有一个正确的方法:

    /// <summary>
    /// Attempts to fill the buffer with the specified number of bytes from the
    /// stream. If there are fewer bytes left in the stream than requested then
    /// all available bytes will be read into the buffer.
    /// </summary>
    /// <param name="stream">Stream to read from.</param>
    /// <param name="buffer">Buffer to write the bytes to.</param>
    /// <param name="offset">Offset at which to write the first byte read from
    ///                      the stream.</param>
    /// <param name="length">Number of bytes to read from the stream.</param>
    /// <returns>Number of bytes read from the stream into buffer. This may be
    ///          less than requested, but only if the stream ended before the
    ///          required number of bytes were read.</returns>
    public static int FillBuffer(this Stream stream,
                                 byte[] buffer, int offset, int length)
    {
        int totalRead = 0;
        while (length > 0)
        {
            var read = stream.Read(buffer, offset, length);
            if (read == 0)
                return totalRead;
            offset += read;
            length -= read;
            totalRead += read;
        }
        return totalRead;
    }

    /// <summary>
    /// Attempts to read the specified number of bytes from the stream. If
    /// there are fewer bytes left before the end of the stream, a shorter
    /// (possibly empty) array is returned.
    /// </summary>
    /// <param name="stream">Stream to read from.</param>
    /// <param name="length">Number of bytes to read from the stream.</param>
    public static byte[] Read(this Stream stream, int length)
    {
        byte[] buf = new byte[length];
        int read = stream.FillBuffer(buf, 0, length);
        if (read < length)
            Array.Resize(ref buf, read);
        return buf;
    }