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


当前回答

对于C/ c++程序员来说,过渡到c#是很自然的事情。然而,我个人遇到的最大的问题(以及其他人在做同样的转换时遇到的问题)是没有完全理解c#中类和结构之间的区别。

在c++中,类和结构是相同的;它们只在默认可见性上有所不同,其中类默认为私有可见性,结构默认为公共可见性。在c++中,这个类定义

    class A
    {
    public:
        int i;
    };

在功能上等价于此结构定义。

    struct A
    {
        int i;
    };

然而,在c#中,类是引用类型,而结构是值类型。这在(1)决定何时使用一个而不是另一个,(2)测试对象的相等性,(3)性能(例如,装箱/拆箱)等方面产生了很大的差异。

网络上有各种各样的信息与两者之间的差异有关(例如,这里)。我强烈建议任何想要过渡到c#的人至少要了解这些差异及其含义。

其他回答

递归属性有问题

我认为不是c#特有的,而且我确信我在SO的其他地方看到过它(这个问题让我想起了它)

它有两种发生方式,但最终结果是一样的:

忘记引用基数。当重写一个属性时:

 public override bool IsRecursive
 {
     get { return IsRecursive; }
     set { IsRecursive = value; }
 }

从auto-属性改为back -属性,但并没有完全改变:

public bool IsRecursive
{
    get { return IsRecursive; }
    set { IsRecursive = value; }
}

ASP。NET:

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

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

看看这个:

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/

在调试环境中求值时,base关键字不能按预期工作:方法调用仍然使用虚拟分派。

当我偶然发现它时,我浪费了很多时间,我以为我遇到了CLR时空中的某种裂缝,但我后来意识到这是一个已知的(甚至有点故意的)bug:

http://blogs.msdn.com/jmstall/archive/2006/06/29/funceval-does-virtual-dispatch.aspx

我一直认为值类型总是在堆栈上,引用类型总是在堆上。

但事实并非如此。当我最近在SO上看到这个问题时(可以说回答是错误的),我才知道事实并非如此。

正如Jon Skeet的回答(引用Eric Lippert的博客文章),这是一个神话。

相当重要的环节:

关于值类型的真相

引用不是aAddress

堆栈是实现细节第1部分

堆栈是实现细节第2部分