我最近正在使用一个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决议
Ticks属性以千万分之一秒(100纳秒块)为单位测量时间,但是分辨率不是100纳秒,而是大约15毫秒。
这段代码:
long now = DateTime.Now.Ticks;
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1);
Console.WriteLine(DateTime.Now.Ticks - now);
}
将给你一个输出(例如):
0
0
0
0
0
0
0
156254
156254
156254
类似地,如果查看DateTime.Now。毫秒,您将得到以15.625毫秒为单位的四舍五入块的值:15、31、46等等。
这种特殊的行为因系统而异,但是在这个日期/时间API中还有其他与解析相关的问题。
路径。结合
一种组合文件路径的好方法,但它并不总是按您期望的方式运行。
如果第二个参数以\字符开头,它不会给你一个完整的路径:
这段代码:
string prefix1 = "C:\\MyFolder\\MySubFolder";
string prefix2 = "C:\\MyFolder\\MySubFolder\\";
string suffix1 = "log\\";
string suffix2 = "\\log\\";
Console.WriteLine(Path.Combine(prefix1, suffix1));
Console.WriteLine(Path.Combine(prefix1, suffix2));
Console.WriteLine(Path.Combine(prefix2, suffix1));
Console.WriteLine(Path.Combine(prefix2, suffix2));
给出如下输出:
C:\MyFolder\MySubFolder\log\
\log\
C:\MyFolder\MySubFolder\log\
\log\
抛出收到异常
一个让许多新开发人员困惑的问题是重新抛出异常语义。
我经常看到如下代码
catch(Exception e)
{
// Do stuff
throw e;
}
问题是它会清除堆栈跟踪,并使诊断问题变得更加困难,因为您无法跟踪异常起源于何处。
正确的代码是不带参数的throw语句:
catch(Exception)
{
throw;
}
或者将异常包装在另一个异常中,并使用内部异常获取原始堆栈跟踪:
catch(Exception e)
{
// Do stuff
throw new MySpecialException(e);
}
类型。方法
我见过的咬了很多人的是Type.GetType(string)。他们想知道为什么它适用于自己程序集中的类型,以及一些类型,如System。字符串,而不是System.Windows.Forms.Form。答案是,它只能在当前程序集中和mscorlib中查找。
匿名方法
c# 2.0引入了匿名方法,导致了下面这种糟糕的情况:
using System;
using System.Threading;
class Test
{
static void Main()
{
for (int i=0; i < 10; i++)
{
ThreadStart ts = delegate { Console.WriteLine(i); };
new Thread(ts).Start();
}
}
}
打印出来的是什么?嗯,这完全取决于日程安排。它会输出10个数字,但它可能不会输出0 1 2 3 4 5 6 7 8 9这是你可能期望的。问题是被捕获的是变量i,而不是它在创建委托时的值。这可以用一个合适范围的额外局部变量轻松解决:
using System;
using System.Threading;
class Test
{
static void Main()
{
for (int i=0; i < 10; i++)
{
int copy = i;
ThreadStart ts = delegate { Console.WriteLine(copy); };
new Thread(ts).Start();
}
}
}
迭代器块的延迟执行
这个“穷人单元测试”没有通过——为什么?
using System;
using System.Collections.Generic;
using System.Diagnostics;
class Test
{
static IEnumerable<char> CapitalLetters(string input)
{
if (input == null)
{
throw new ArgumentNullException(input);
}
foreach (char c in input)
{
yield return char.ToUpper(c);
}
}
static void Main()
{
// Test that null input is handled correctly
try
{
CapitalLetters(null);
Console.WriteLine("An exception should have been thrown!");
}
catch (ArgumentNullException)
{
// Expected
}
}
}
答案是,在迭代器的MoveNext()方法第一次被调用之前,CapitalLetters代码源中的代码不会被执行。
我的脑筋急转弯页面上还有一些奇怪的东西。