我最近正在使用一个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#陷阱分类会很有用。
DateTime.ToString(“dd / MM / yyyy”);这实际上不会总是给你dd/MM/yyyy,而是会考虑到区域设置,并根据你所在的位置替换你的日期分隔符。你可能得到dd-MM-yyyy或类似的东西。
正确的方法是使用DateTime.ToString("dd'/'MM'/'yyyy");
DateTime.ToString(“r”)应该转换为使用GMT的RFC1123。GMT距离UTC只有几分之一秒,但是“r”格式说明符不会转换为UTC,即使问题中的DateTime指定为Local。
这将导致以下gotcha(取决于您的本地时间与UTC的距离):
DateTime.Parse("Tue, 06 Sep 2011 16:35:12 GMT").ToString("r")
> "Tue, 06 Sep 2011 17:35:12 GMT"
哎呀!
也许不是真的抓住你,因为行为写得很清楚在MSDN中,但已经打破了我的脖子,因为我发现它相当反直觉:
Image image = System.Drawing.Image.FromFile("nice.pic");
这家伙留下了“不错”。图片“文件锁定,直到图像被处置。在我面对它的时候,我认为它会很好地加载图标,并没有意识到(一开始),我最终有几十个打开和锁定的文件!Image一直跟踪它从哪里加载文件…
如何解决这个问题?我以为只用一行就行了。我期望FromFile()有一个额外的参数,但没有,所以我写了这个…
using (Stream fs = new FileStream("nice.pic", FileMode.Open, FileAccess.Read))
{
image = System.Drawing.Image.FromStream(fs);
}
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写得很好的和有用的帖子,但它仍然有点奇怪。你同意吗?
合同在流。阅读是我见过很多人被绊倒的东西:
// 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;
}