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


当前回答

一些代码:

        List<int> a = new List<int>();
        for (int i = 0; i < 10; i++)
        {
            a.Add(i);
        }

        var q1 = (from aa in a
                  where aa == 2
                  select aa).Single();

        var q2 = (from aa in a
                  where aa == 2
                  select aa).First();

q1 -在这个查询中检查List中的所有整数; Q2 -检查整数,直到找到“正确的”整数。

其他回答

静态构造函数在锁定状态下执行。因此,从静态构造函数调用线程代码可能会导致死锁。 下面是一个例子:

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() { }
}

不是最糟糕的,但还没被提起。工厂方法作为参数传递给System.Collections.Concurrent方法可以被多次调用,即使只使用了一个返回值。考虑到. net在线程原语中多么强烈地试图保护您不受虚假唤醒的影响,这可能会让您感到惊讶。

using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ValueFactoryBehavingBadlyExample
{
    class Program
    {
        static ConcurrentDictionary<int, int> m_Dict = new ConcurrentDictionary<int, int>();
        static ManualResetEventSlim m_MRES = new ManualResetEventSlim(false);
        static void Main(string[] args)
        {
            for (int i = 0; i < 8; ++i)
            {
                Task.Factory.StartNew(ThreadGate, TaskCreationOptions.LongRunning);
            }
            Thread.Sleep(1000);
            m_MRES.Set();
            Thread.Sleep(1000);
            Console.WriteLine("Dictionary Size: " + m_Dict.Count);
            Console.Read();
        }

        static void ThreadGate()
        {
            m_MRES.Wait();
            int value = m_Dict.GetOrAdd(0, ValueFactory);
        }

        static int ValueFactory(int key)
        {
            Thread.Sleep(1000);
            Console.WriteLine("Value Factory Called");
            return key;
        }
    }
}

(可能)输出:

Value Factory Called
Value Factory Called
Value Factory Called
Value Factory Called
Dictionary Size: 0
Value Factory Called
Value Factory Called
Value Factory Called
Value Factory Called

当可见改变时,通常不调用VisibleChanged。

可枚举对象可以计算不止一次

当您有一个惰性枚举的可枚举对象,并且对其进行两次迭代并得到不同的结果时,它会咬您一口。(或者你得到相同的结果,但它执行两次不必要的)

例如,在编写某个测试时,我需要一些临时文件来测试逻辑:

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 !!然后,当....时,您开始严格检查是否没有竞态条件浪费了一个小时之后……你发现这只是一个微小的可枚举的东西,你忘记了....

一些代码:

        List<int> a = new List<int>();
        for (int i = 0; i < 10; i++)
        {
            a.Add(i);
        }

        var q1 = (from aa in a
                  where aa == 2
                  select aa).Single();

        var q2 = (from aa in a
                  where aa == 2
                  select aa).First();

q1 -在这个查询中检查List中的所有整数; Q2 -检查整数,直到找到“正确的”整数。