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

我最近正在处理一个DateTime对象,并编写了如下内容:


DateTime dt = DateTime.Now;

dt.AddDays(1);

return dt; // still today's date! WTF?

的intellisense文档AddDays()说,它在日期上添加了一天,但实际上并没有-实际返回的日期中添加了一天,因此您必须这样写:


DateTime dt = DateTime.Now;

dt = dt.AddDays(1);

return dt; // tomorrow's date

之前,这已经咬了我很多次,所以我认为对最糟糕的C#陷阱进行分类将很有用。


红糖糍粑
浏览 726回答 3
3回答

慕尼黑8549860

private int myVar;public int MyVar{    get { return MyVar; }}布拉莫 您的应用崩溃,没有堆栈跟踪。一直发生。(注意使用大写MyVar字母而不是小写字母myVar)。

千万里不及你

Type.GetType我看到很多人咬过的是Type.GetType(string)。他们想知道为什么它适用于他们自己的程序集中的类型,而某些类型像System.String,而不是System.Windows.Forms.Form。答案是,它只在当前程序集中和中出现mscorlib。匿名方法C#2.0引入了匿名方法,导致了如下讨厌的情况:using System;using System.Threading;class Test{&nbsp; &nbsp; static void Main()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; for (int i=0; i < 10; i++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ThreadStart ts = delegate { Console.WriteLine(i); };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Thread(ts).Start();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}那会打印出什么?好吧,这完全取决于调度。它会打印10个数字,但可能不会打印0、1、2、3、4、5、6、7、8、9,这可能是您期望的。问题在于i捕获的变量是它,而不是在创建委托时的值。使用正确范围的额外局部变量可以轻松解决此问题:using System;using System.Threading;class Test{&nbsp; &nbsp; static void Main()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; for (int i=0; i < 10; i++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int copy = i;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ThreadStart ts = delegate { Console.WriteLine(copy); };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Thread(ts).Start();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}推迟执行迭代器块这个“穷人的单元测试”没有通过-为什么不呢?using System;using System.Collections.Generic;using System.Diagnostics;class Test{&nbsp; &nbsp; static IEnumerable<char> CapitalLetters(string input)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (input == null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentNullException(input);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; foreach (char c in input)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield return char.ToUpper(c);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; static void Main()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Test that null input is handled correctly&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CapitalLetters(null);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine("An exception should have been thrown!");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch (ArgumentNullException)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Expected&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}答案是,CapitalLetters直到MoveNext()首次调用迭代器的方法时,代码源中的代码才会执行。我的脑筋急转弯页面上还有其他怪异之处。

慕田峪7331174

重新抛出异常重新抛出异常语义是获得许多新开发人员的陷阱。很多时间我看到如下代码catch(Exception e)&nbsp;{&nbsp; &nbsp;// Do stuff&nbsp;&nbsp; &nbsp;throw e;&nbsp;}问题在于,它会擦除堆栈跟踪,并使诊断问题变得更加困难,导致您无法跟踪异常的起源。正确的代码是不带参数的throw语句:catch(Exception){&nbsp; &nbsp; throw;}或将异常包装在另一个异常中,然后使用内部异常获取原始堆栈跟踪:catch(Exception e)&nbsp;{&nbsp; &nbsp;// Do stuff&nbsp;&nbsp; &nbsp;throw new MySpecialException(e);&nbsp;}
打开App,查看更多内容
随时随地看视频慕课网APP