C#或.NET中最糟糕的陷阱是什么?

384

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


158
返回 DateTime.Now 增加一天后的日期。 - crashmstr
24
据我所知,内置值类型都是不可变的,至少在该类型包含的任何方法中,返回的都是一个新项,而不是修改现有项。至少,我想不到有一个不这样做的(方法):所有这些行为都非常一致。 - Joel Coehoorn
6
可变值类型:System.Collections.Generics.List.Enumerator。 (如果你尝试得足够努力,你会看到它表现得很奇怪。) - Jon Skeet
14
智能感知会为你提供所需的所有信息。它表明返回一个DateTime对象。如果它只是改变了你传入的对象,那么它就是一个void方法。 - John Kraft
22
不一定:例如,StringBuilder.Append(...)返回“this”,这在流畅接口中非常常见。 - Jon Skeet
显示剩余10条评论
61个回答

10
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!"

是的,这种行为是有文档记录的,但这并不意味着它是正确的。


6
我不同意 - 当一个单词全部大写,它可能有特殊的含义,你不想用标题格式搞乱它,例如 "president of the USA" -> "President Of The USA",而不是 "President Of The Usa"。 - Shaul Behr
6
@Shaul: 在这种情况下,他们应该将此作为参数进行说明,以避免混淆,因为我从未遇到过任何人事先预期这种行为 - 这使得它成为一个 - BlueRaja - Danny Pflughoeft

9
今日免费次数已满, 请开通会员/明日再来

是的,如果你不小心,流可能会咬你。我曾经有一个非常糟糕的习惯,就是不记得关闭它们。 - MusiGenesis
3
@MusiGenesis,使用 using(Stream stream = new ...) { } 的方式。 - tuinstoel

8

Dictionary<,>: “返回项的顺序是未定义的”。这很糟糕,因为有时它会给你带来麻烦,但有时又能正常工作。如果你盲目地假设Dictionary会表现得很好(“为什么不呢?我想,List也是这样的”),那么你真的必须深入了解它,才能最终开始质疑自己的假设。

(类似问题请参见此处。)


11
当然,List<T>很好用。如果你需要保持项目的顺序,请使用SortedDictionary<T>。 - Allon Guralnek
List<T> 会维护添加项目的顺序,但是当您调用 GetEnumerator(即在 foreach 循环中)时,返回的枚举器不能保证保留顺序。在处理时,您必须通过索引循环以保证顺序。 - cjk
1
@ck,你有那个链接吗?我相信很多人会感到惊讶... - Benjol
3
@ck:错误。List<T>.GetEnumerator 确实 保留顺序。 - SLaks
1
我认为@ck是在暗示合同中没有保证枚举将按顺序进行。 - user1228
显示剩余2条评论

8

有一本关于.NET陷阱的书《.NET Gotchas》

我最喜欢的是这个:你在C#中创建一个类,继承到VB中,然后试图重新继承回C#,但它无法工作。让人抓狂。


我猜这纯粹是 Visual Studio 的怪异之处。 - Anton Gogolev
这很有趣...安东可能是对的。 - Big Endian
2
我不认为这是一个陷阱,而是一个有用的功能! - nawfal
我认为这就像将英语翻译成法语,然后再翻译回英语一样。你通常不会得到完全相同的结果。 - Dan Bechard

7

静态构造函数在锁定下执行。因此,从静态构造函数调用线程代码可能会导致死锁。

以下是一个示例,演示了这一点:

using System.Threading;
class Blah
{
    static void Main() { /* Won’t run because the static constructor deadlocks. */ }

    static Blah()
    {
        Thread thread = new Thread(ThreadBody);
        thread.Start();
        thread.Join();
    }

    static void ThreadBody() { }
}

7

7

6
如果你正在为MOSS编写代码,且通过以下方式获取了站点引用:
SPSite oSiteCollection = SPContext.Current.Site;

然后在你的代码中你会这样写:

oSiteCollection.Dispose();

来自MSDN

如果您创建了一个SPSite对象,您可以使用Dispose方法关闭该对象。但是,如果您拥有对共享资源的引用,例如通过GetContextSite方法或Site属性提供对象(例如SPContext.Current.Site),请不要使用Dispose方法关闭该对象,而是允许Windows SharePoint Services或您的门户应用程序管理该对象。有关对象处理的更多信息,请参见最佳实践:使用可处理的Windows SharePoint Services对象。

这在每个MOSS程序员的某个时候都会发生。


那么当您处理它时会发生什么?您会关闭整个网站吗? - Chris Marisic
你失去了对该站点的引用。 - cciotti

6

ASP.NET:

如果您正在使用 Linq-To-SQL,当您在数据上下文上调用 SubmitChanges() 并出现异常(例如重复键或其他约束违规),那么有问题的对象值将保留在内存中,而您正在调试时,并且每次您随后调用 SubmitChanges() 时都会重新提交。

现在这是一个真正的棘手问题:即使您在 IDE 中按下“停止”按钮并重新启动,不良值仍将留在内存中!我不明白为什么有人认为这是一个好主意——但是在系统托盘中弹出的那个小 ASP.NET 图标仍然运行,并且似乎保存了您的对象缓存。如果您想清空内存空间,则必须右键单击该图标并强制关闭它!要注意!


你肯定是指暂停,而不是停止。 - Amy B
David - 不,我的意思是我说的话。即使你按下“停止”按钮,小的ASP.NET图标仍然在任务栏中运行。这就是为什么它是一个陷阱! - Shaul Behr
1
因为第一部分的原因,+1,没有独立了解踢球者的知识。 - Maslow

5
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成员都在这里提到了。它应该检查所有枚举成员,如果一个成员在switch语句中不存在,那么这样的错误才有意义,但现在我必须添加一个冗余的Default case,而且永远不会被代码执行到。

编辑:
经过更多的研究,我发现了Eric Lippert写得很好且有用的文章,但它仍然有点奇怪。你同意吗?


2
默认情况下,这段代码HowYouFeel(42);将被执行。是的,虽然没有针对42的枚举,但它仍然是有效的。.NET不会将枚举类型限制为定义的值,并且可以传递来自枚举的基本类型(在本例中为整数)的值。 - Bradley Uffner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接