我最近正在使用一个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#陷阱分类会很有用。
类型。方法
我见过的咬了很多人的是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代码源中的代码不会被执行。
我的脑筋急转弯页面上还有一些奇怪的东西。
看看这个:
class Program
{
static void Main(string[] args)
{
var originalNumbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var list = new List<int>(originalNumbers);
var collection = new Collection<int>(originalNumbers);
originalNumbers.RemoveAt(0);
DisplayItems(list, "List items: ");
DisplayItems(collection, "Collection items: ");
Console.ReadLine();
}
private static void DisplayItems(IEnumerable<int> items, string title)
{
Console.WriteLine(title);
foreach (var item in items)
Console.Write(item);
Console.WriteLine();
}
}
输出是:
List items: 123456
Collection items: 23456
接受IList的集合构造函数会对原始List创建一个包装器,而List构造函数会创建一个新List并将所有引用从原始List复制到新List。
点击这里查看更多信息:
http://blog.roboblob.com/2012/09/19/dot-net-gotcha-nr1-list-versus-collection-constructor/
也许不是真的抓住你,因为行为写得很清楚在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);
}