我最近正在使用一个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#陷阱分类会很有用。
相关对象和外键不同步
微软已经承认了这个漏洞。
我有一个类Thing,它有一个FK到Category。Category与Thing之间没有定义的关系,以免污染接口。
var thing = CreateThing(); // does stuff to create a thing
var category = GetCategoryByID(123); // loads the Category with ID 123
thing.Category = category;
Console.WriteLine("Category ID: {0}", thing.CategoryID);
输出:
Category ID: 0
类似的:
var thing = CreateThing();
thing.CategoryID = 123;
Console.WriteLine("Category name: {0}", order.Category.Name);
抛出NullReferenceException。相关对象Category不加载ID为123的Category记录。
但是,在向DB提交更改之后,这些值将得到同步。但是在您访问DB之前,FK值和相关对象的功能实际上是独立的!
(有趣的是,同步FK值与相关对象的失败似乎只发生在没有定义子关系的情况下,即Category没有“Things”属性。但当你只是设置FK值时,“按需加载”永远不会起作用。)
明白了!
可枚举对象可以计算不止一次
当您有一个惰性枚举的可枚举对象,并且对其进行两次迭代并得到不同的结果时,它会咬您一口。(或者你得到相同的结果,但它执行两次不必要的)
例如,在编写某个测试时,我需要一些临时文件来测试逻辑:
var files = Enumerable.Range(0, 5)
.Select(i => Path.GetTempFileName());
foreach (var file in files)
File.WriteAllText(file, "HELLO WORLD!");
/* ... many lines of codes later ... */
foreach (var file in files)
File.Delete(file);
想象一下当file . delete (file)抛出FileNotFound时我的惊讶!!
这里发生的情况是,可枚举的文件被迭代了两次(第一次迭代的结果根本没有被记住),在每次新的迭代中,您将重新调用Path.GetTempFilename(),因此您将得到一组不同的临时文件名。
当然,解决方案是使用ToArray()或ToList()快速枚举值:
var files = Enumerable.Range(0, 5)
.Select(i => Path.GetTempFileName())
.ToArray();
当你在做一些多线程的事情时,这甚至更可怕,比如:
foreach (var file in files)
content = content + File.ReadAllText(file);
你会发现内容。在所有写入之后,长度仍然为0 !!然后,当....时,您开始严格检查是否没有竞态条件浪费了一个小时之后……你发现这只是一个微小的可枚举的东西,你忘记了....
我来这个派对有点晚了,但我最近有两个问题都困扰着我:
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\