我最近使用的是DateTime
对象,并写了类似这样的内容:
DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?
AddDays()
的intellisense文档说它在日期中添加了一天,但它没有 - 它实际上返回添加了一天的日期,所以你必须写得像:
DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date
之前我曾多次咬过我,所以我认为编制最糟糕的C#陷阱会很有用。
答案 0 :(得分:299)
private int myVar;
public int MyVar
{
get { return MyVar; }
}
Blammo。您的应用程序崩溃,没有堆栈跟踪。一直发生。
(注意资本MyVar
而不是getter中的小写myVar
。)
答案 1 :(得分:251)
<强> Type.GetType 强>
我见过的人咬了很多人Type.GetType(string)
。他们想知道为什么它适用于自己的程序集中的类型,以及某些类型,如System.String
,但不是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
}
}
}
答案是CapitalLetters
代码源代码中的代码在第一次调用迭代器的MoveNext()
方法之前不会执行。
我的brainteasers page还有其他一些奇怪的东西。
答案 2 :(得分:192)
获得大量新开发人员的问题是重新抛出异常语义。
很多时候我看到如下代码
catch(Exception e)
{
// Do stuff
throw e;
}
问题在于它擦除了堆栈跟踪并使诊断问题更加困难,导致您无法跟踪异常发生的位置。
正确的代码是没有args的throw语句:
catch(Exception)
{
throw;
}
或者将异常包装在另一个异常中,并使用内部异常来获取原始堆栈跟踪:
catch(Exception e)
{
// Do stuff
throw new MySpecialException(e);
}
答案 3 :(得分:192)
海森堡观察窗口
如果您正在进行按需加载的操作,这可能会让您感到非常痛苦,例如:
private MyClass _myObj;
public MyClass MyObj {
get {
if (_myObj == null)
_myObj = CreateMyObj(); // some other code to create my object
return _myObj;
}
}
现在让我们假设你在其他地方使用了一些代码:
// blah
// blah
MyObj.DoStuff(); // Line 3
// blah
现在您要调试CreateMyObj()
方法。所以你在上面的第3行放了一个断点,打算进入代码。只是为了好的衡量标准,你还在_myObj = CreateMyObj();
上方的一行上设置断点,甚至在CreateMyObj()
内部设置一个断点。
代码在第3行遇到你的断点。你进入代码。您希望输入条件代码,因为_myObj
显然为空,对吧?呃...那么......为什么它跳过这个条件并直接进入return _myObj
?!你将鼠标悬停在_myObj上......事实上,它确实有价值!这是怎么发生的?!
答案是你的IDE导致它获得一个值,因为你打开了一个“监视”窗口 - 特别是“Autos”监视窗口,它显示与当前或上一行相关的所有变量/属性的值执行。当你在第3行遇到断点时,观察窗口决定你有兴趣知道MyObj
的价值 - 所以在幕后,忽略你的任何断点,它会去为您计算MyObj
的值 - 包括设置_myObj值的CreateMyObj()
的调用!
这就是我称之为海森堡观察窗的原因 - 你不能在不影响它的情况下观察它的价值...... :)
<强> GOTCHA!强>
编辑 - 我觉得@ChristianHayter的评论值得包含在主要答案中,因为它看起来像是这个问题的有效解决方法。所以,只要你有一个懒惰的属性......
使用[DebuggerBrowsable(DebuggerBrowsableState.Never)]或[DebuggerDisplay(“&lt;按需加载&gt;”)]装饰您的属性。 - 克里斯蒂安·海特
答案 4 :(得分:143)
这是另一个让我受益的时间:
static void PrintHowLong(DateTime a, DateTime b)
{
TimeSpan span = a - b;
Console.WriteLine(span.Seconds); // WRONG!
Console.WriteLine(span.TotalSeconds); // RIGHT!
}
TimeSpan.Seconds是时间跨度的秒部分(2分0秒的秒值为0)。
TimeSpan.TotalSeconds是以秒为单位测量的整个时间跨度(2分钟的总秒数值为120)。
答案 5 :(得分:79)
因为你没有解除事件的连接而导致内存泄漏。
这甚至让我认识的一些高级开发人员感到高兴。
想象一下包含很多内容的WPF表单,在那里你订阅了一个事件。如果您没有取消订阅,则在关闭和取消引用后,整个表单将保留在内存中。
我相信我看到的问题是在WPF表单中创建一个DispatchTimer并订阅Tick事件,如果你没有 - =在计时器上你的表单会泄漏内存!
在此示例中,您的拆卸代码应该
timer.Tick -= TimerTickEventHandler;
这个特别棘手,因为你在WPF表单中创建了DispatchTimer的实例,所以你会认为它是垃圾收集过程处理的内部引用...不幸的是,DispatchTimer使用静态内部列表UI线程上的订阅和服务请求,因此引用由静态类“拥有”。
答案 6 :(得分:62)
也许不是真的有问题,因为这种行为在MSDN中写得很清楚,但是我的脖子已经打破了一次,因为我发现它反直觉:
Image image = System.Drawing.Image.FromFile("nice.pic");
此人将"nice.pic"
文件锁定,直到图像被丢弃。在我遇到它的时候,我虽然在飞行中加载图标并且没有意识到(起初)我最终得到了数十个打开和锁定的文件会很好!图像跟踪它从...加载文件的位置
如何解决这个问题?我以为一个班轮就可以完成这项任务。我期待FromFile()
的额外参数,但没有,所以我写了这个......
using (Stream fs = new FileStream("nice.pic", FileMode.Open, FileAccess.Read))
{
image = System.Drawing.Image.FromStream(fs);
}
答案 7 :(得分:51)
如果算上ASP.NET,我会说webforms生命周期对我来说是一个非常大的问题。我花了无数个小时来调试写得不好的webforms代码,只是因为很多开发人员并不真正了解何时使用哪个事件处理程序(遗憾的是我包括在内)。
答案 8 :(得分:47)
重载==运算符和无类型容器(arraylists,数据集等):
string my = "my ";
Debug.Assert(my+"string" == "my string"); //true
var a = new ArrayList();
a.Add(my+"string");
a.Add("my string");
// uses ==(object) instead of ==(string)
Debug.Assert(a[1] == "my string"); // true, due to interning magic
Debug.Assert(a[0] == "my string"); // false
解决方案?
在比较字符串类型时始终使用string.Equals(a, b)
使用List<string>
等泛型来确保两个操作数都是字符串。
答案 9 :(得分:46)
<强>则DateTime.ToString( “DD / MM / YYYY”)强>;这实际上不总是给你dd / MM / yyyy但是它会考虑区域设置并根据你的位置替换日期分隔符。所以你可能会得到dd-MM-yyyy或类似的东西。
正确的方法是使用 DateTime.ToString(“dd'/'MM'/'yyyy”);
DateTime.ToString(“r”)应该转换为使用GMT的RFC1123。格林尼治标准时间距离UTC只有几分之一秒,而“r”格式说明符does not convert to UTC,即使有问题的日期时间被指定为本地。
这导致以下问题(取决于您当地时间与UTC的距离):
DateTime.Parse("Tue, 06 Sep 2011 16:35:12 GMT").ToString("r")
> "Tue, 06 Sep 2011 17:35:12 GMT"
糟糕!
答案 10 :(得分:45)
[Serializable]
class Hello
{
readonly object accountsLock = new object();
}
//Do stuff to deserialize Hello with BinaryFormatter
//and now... accountsLock == null ;)
故事的道德:反序列化对象时不会运行字段初始化程序
答案 11 :(得分:44)
前几天我看到这张贴了,我觉得它很晦涩,对那些不知道的人来说很痛苦
int x = 0;
x = x++;
return x;
因为它将返回0而不是大多数人所期望的
答案 12 :(得分:40)
我参加这个派对有点晚了,但是我最近有两个陷入困境的陷阱:
Ticks属性测量时间为百万分之一秒(100纳秒块),但分辨率不是100纳秒,大约是15毫秒。
此代码:
long now = DateTime.Now.Ticks;
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1);
Console.WriteLine(DateTime.Now.Ticks - now);
}
会给你一个输出(例如):
0
0
0
0
0
0
0
156254
156254
156254
同样,如果你看看DateTime.Now.Millisecond,你将获得15.625ms的圆形块值:15,31,46等。
此特定行为varies from system to system,但此日期/时间API中的there are other resolution-related gotchas。
组合文件路径的好方法,但它并不总是按照您期望的方式运行。
如果第二个参数以\
字符开头,则不会为您提供完整的路径:
此代码:
string prefix1 = "C:\\MyFolder\\MySubFolder";
string prefix2 = "C:\\MyFolder\\MySubFolder\\";
string suffix1 = "log\\";
string suffix2 = "\\log\\";
Console.WriteLine(Path.Combine(prefix1, suffix1));
Console.WriteLine(Path.Combine(prefix1, suffix2));
Console.WriteLine(Path.Combine(prefix2, suffix1));
Console.WriteLine(Path.Combine(prefix2, suffix2));
给你这个输出:
C:\MyFolder\MySubFolder\log\
\log\
C:\MyFolder\MySubFolder\log\
\log\
答案 13 :(得分:37)
当您启动一个写入控制台的进程(使用System.Diagnostics),但您从未阅读过Console.Out流时,在一定量的输出后,您的应用程序将显示为挂起。
答案 14 :(得分:34)
Linq-To-Sql中没有操作员快捷方式
请参阅here。
简而言之,在Linq-To-Sql查询的条件子句中,您不能使用||
和&&
等条件快捷方式来避免空引用异常;即使第一个条件不需要评估第二个条件,Linq-To-Sql也会对OR或AND运算符的两边进行求值!
答案 15 :(得分:29)
使用虚拟方法的默认参数
abstract class Base
{
public virtual void foo(string s = "base") { Console.WriteLine("base " + s); }
}
class Derived : Base
{
public override void foo(string s = "derived") { Console.WriteLine("derived " + s); }
}
...
Base b = new Derived();
b.foo();
输出:
派生基地
答案 16 :(得分:27)
struct Point { ... }
List<Point> mypoints = ...;
mypoints[i].x = 10;
无效。
mypoints[i]
返回Point
值对象的副本。 C#happily允许您修改副本的字段。默默无闻。
<强>更新强> 这似乎是在C#3.0中修复的:
Cannot modify the return value of 'System.Collections.Generic.List<Foo>.this[int]' because it is not a variable
答案 17 :(得分:25)
也许不是最糟糕的,但是.net框架use degrees的某些部分,而其他部分使用radians (并且Intellisense出现的文档从不告诉您哪个,您必须访问MSDN找出
所有这一切都可以通过Angle
班而不是......
答案 18 :(得分:22)
对于C / C ++程序员来说,过渡到C#是很自然的。然而,我遇到的最大问题(并且已经与其他人一起进行过相同的转换)并没有完全理解C#中类和结构之间的区别。
在C ++中,类和结构是相同的;它们仅在默认可见性方面有所不同,其中类默认为私有可见性,而结构默认为公共可见性。在C ++中,这个类定义
class A
{
public:
int i;
};
在功能上等同于此结构定义。
struct A
{
int i;
};
但是,在C#中,类是引用类型,而结构是值类型。这会产生 BIG 差异(1)决定何时使用其中一个,(2)测试对象相等,(3)性能(例如装箱/拆箱)等。
网络上有各种与两者之间的差异相关的信息(例如here)。我强烈建议任何过渡到C#的人至少要了解差异及其影响。
答案 19 :(得分:19)
垃圾收集和Dispose()。虽然您不必做任何事情来释放内存,但您仍然需要通过Dispose()释放资源。当您使用WinForms或以任何方式跟踪对象时,这是一个非常容易忘记的事情。
答案 20 :(得分:18)
令人讨厌的Linq Caching Gotcha
导致此次发现的my question和发现此问题的the blogger。
简而言之,DataContext保留了您加载的所有Linq-to-Sql对象的缓存。如果其他人对您之前加载的记录进行了任何更改,即使您明确重新加载记录,也无法获取最新数据
这是因为DataContext上有一个名为ObjectTrackingEnabled
的属性,默认情况下为true。如果您将该属性设置为false,则每次都会重新加载记录... 但是 ...您无法使用SubmitChanges()保留对该记录的任何更改。
<强> GOTCHA!强>
答案 21 :(得分:18)
阵列实施IList
但是不要实现它。当您调用Add时,它会告诉您它不起作用。那么为什么一个类在它不能支持时实现一个接口呢?
编译,但不起作用:
IList<int> myList = new int[] { 1, 2, 4 };
myList.Add(5);
我们经常遇到这个问题,因为序列化程序(WCF)将所有IList转换为数组,并且我们遇到运行时错误。
答案 22 :(得分:18)
MS SQL Server无法处理1753年之前的日期。重要的是,这与.NET DateTime.MinDate
常量(1/1/1)不同步。因此,如果你试图保存一个思想,一个畸形的日期(最近发生在我的数据导入中)或者仅仅是征服者威廉的出生日期,你就会遇到麻烦。没有内置的解决方法;如果您可能需要在1753年之前使用日期,则需要编写自己的解决方法。
答案 23 :(得分:18)
foreach循环变量范围!
var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
l.Add(() => s);
}
foreach (var a in l)
Console.WriteLine(a());
打印五个“amet”,而以下示例正常工作
var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
var t = s;
l.Add(() => t);
}
foreach (var a in l)
Console.WriteLine(a());
答案 24 :(得分:17)
Stream.Read 上的合同是我见过很多人的事情:
// Read 8 bytes and turn them into a ulong
byte[] data = new byte[8];
stream.Read(data, 0, 8); // <-- WRONG!
ulong data = BitConverter.ToUInt64(data);
这是错误的原因是Stream.Read
将读取最多指定的字节数,但完全免费只能读取1个字节,甚至如果在流结束之前有另外7个字节可用。
这看起来与Stream.Write
非常相似没有帮助, 保证在没有异常的情况下返回时写入所有字节。上述代码几乎一直在工作也无济于事。当然,没有现成的,方便的方法可以正确读取N个字节。
所以,为了堵塞漏洞,并提高对此的认识,这里有一个正确的方法来做这个例子:
/// <summary>
/// Attempts to fill the buffer with the specified number of bytes from the
/// stream. If there are fewer bytes left in the stream than requested then
/// all available bytes will be read into the buffer.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="buffer">Buffer to write the bytes to.</param>
/// <param name="offset">Offset at which to write the first byte read from
/// the stream.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
/// <returns>Number of bytes read from the stream into buffer. This may be
/// less than requested, but only if the stream ended before the
/// required number of bytes were read.</returns>
public static int FillBuffer(this Stream stream,
byte[] buffer, int offset, int length)
{
int totalRead = 0;
while (length > 0)
{
var read = stream.Read(buffer, offset, length);
if (read == 0)
return totalRead;
offset += read;
length -= read;
totalRead += read;
}
return totalRead;
}
/// <summary>
/// Attempts to read the specified number of bytes from the stream. If
/// there are fewer bytes left before the end of the stream, a shorter
/// (possibly empty) array is returned.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
public static byte[] Read(this Stream stream, int length)
{
byte[] buf = new byte[length];
int read = stream.FillBuffer(buf, 0, length);
if (read < length)
Array.Resize(ref buf, read);
return buf;
}
答案 25 :(得分:14)
今天我修复了一个长期躲避的错误。该错误位于多线程场景中使用的泛型类中,而静态int字段用于使用Interlocked提供无锁同步。该错误是由于类型的泛型类的每个实例化都有自己的静态引起的。所以每个线程都有自己的静态字段,并没有按预期使用锁。
class SomeGeneric<T>
{
public static int i = 0;
}
class Test
{
public static void main(string[] args)
{
SomeGeneric<int>.i = 5;
SomeGeneric<string>.i = 10;
Console.WriteLine(SomeGeneric<int>.i);
Console.WriteLine(SomeGeneric<string>.i);
Console.WriteLine(SomeGeneric<int>.i);
}
}
这打印 五 10 5
答案 26 :(得分:14)
<强>事件强>
我从未理解为什么事件是语言功能。它们使用起来很复杂:你需要在调用之前检查null,你需要取消注册(你自己),你无法找到谁注册了(例如:我注册了吗?)。为什么事件不是图书馆中的一个类?基本上是专门的List<delegate>
?
答案 27 :(得分:13)
刚刚找到一个让我陷入调试一段时间的奇怪的事情:
您可以为可空int添加null而不抛出异常,并且该值保持为null。
int? i = null;
i++; // I would have expected an exception but runs fine and stays as null
答案 28 :(得分:13)
可以多次评估枚举数
当你有一个懒惰枚举的枚举并且你迭代两次并得到不同的结果时,它会咬你。 (或者你获得相同的结果但不必要地执行两次)
例如,在编写某个测试时,我需要一些临时文件来测试逻辑:
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
!!
这里发生的事情是files
枚举被迭代两次(第一次迭代的结果只是不记住)并且在每次新的迭代中你我要重新调用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);
并且在所有写入之后你发现content.Length
仍然是0!然后,你开始严格检查你没有竞争条件......在一个浪费时间之后......你发现它只是那个小小的可疑的东西你忘记了......
答案 29 :(得分:9)
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!"
是的,记录了这种行为,但这肯定不是正确的。
答案 30 :(得分:8)
Dictionary&lt;,&gt;:“返回项目的顺序未定义”。这太可怕了,因为它有时可能会咬你,但是工作别人,如果你只是盲目地认为字典会发挥得很好(“为什么不应该呢?我想,List会这样做”),你真的需要在你最终开始质疑你的假设之前,请先了解它。
(类似问题here。)
答案 31 :(得分:8)
这是一个超级陷阱,我浪费了2天的故障排除。它没有抛出任何例外,它只是使用weird error messages崩溃了网络服务器。我无法在DEV中重现该问题。此外,项目构建设置的实验以某种方式使它在PROD中消失,然后又回来了。最后我明白了。
如果您在以下代码中看到问题,请告诉我:
private void DumpError(Exception exception, Stack<String> context)
{
if (context.Any())
{
Trace.WriteLine(context.Pop());
Trace.Indent();
this.DumpError(exception, context);
Trace.Unindent();
}
else
{
Trace.WriteLine(exception.Message);
}
}
所以,如果你重视自己的理智:
<强> !!!从来没有对Trace方法提出任何逻辑!!!
代码必须如下所示:
private void DumpError(Exception exception, Stack<String> context)
{
if (context.Any())
{
var popped = context.Pop();
Trace.WriteLine(popped);
Trace.Indent();
this.DumpError(exception, context);
Trace.Unindent();
}
else
{
Trace.WriteLine(exception.Message);
}
}
答案 32 :(得分:8)
我最喜欢的是你在C#中创建一个类,将它继承到VB然后尝试重新继承回C#并且它不起作用。 ARGGH
答案 33 :(得分: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() { }
}
答案 34 :(得分:7)
在调试环境中评估时,base
关键字无法按预期工作:方法调用仍使用虚拟调度。
当我偶然发现它时,我浪费了很多时间,我以为我在CLR的时空中遇到了某种裂痕,但我意识到这是一个已知的(甚至有点故意的)错误:
http://blogs.msdn.com/jmstall/archive/2006/06/29/funceval-does-virtual-dispatch.aspx
答案 35 :(得分:7)
如果您处于设计模式,则所有UserControl中的DesignMode属性都会not actually tell you。
答案 36 :(得分:7)
MemoryStream.GetBuffer()
vs MemoryStream.ToArray()
。前者返回整个缓冲区,后者只是使用过的部分。呸。
答案 37 :(得分:6)
<强> ASP.NET:强>
如果您使用的是Linq-To-SQL,则在数据上下文中调用SubmitChanges()
并抛出异常(例如重复键或其他约束违规),当您使用时,有问题的对象值会保留在您的内存中调试,每次随后拨打SubmitChanges()
时都会重新提交。
现在这里是真正的踢球者:即使您在IDE中按下“停止”按钮并重新启动,错误的值仍将保留在内存中 我不明白为什么有人认为这是一个好主意 - 但是系统托盘中弹出的那个小的ASP.NET图标仍然在运行,它似乎可以保存你的对象缓存。如果要刷新内存空间,则必须右键单击该图标并强制关闭它!的 GOTCHA!强>
答案 38 :(得分: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程序员都会遇到这种情况。
答案 39 :(得分:5)
我经常要提醒自己DateTime是一个值类型,而不是ref类型。对我来说似乎太奇怪了,特别是考虑到它的各种构造函数。
答案 40 :(得分:5)
对于LINQ-to-SQL和LINQ-to-Entities
return result = from o in table
where o.column == null
select o;
//Returns all rows where column is null
int? myNullInt = null;
return result = from o in table
where o.column == myNullInt
select o;
//Never returns anything!
LINQ-to-Entites here有一个错误报告,虽然它们似乎不经常查看该论坛。也许有人应该为LINQ-to-SQL提交一个文件?
答案 41 :(得分:5)
检查一下:
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并将所有引用从原始列表复制到新列表。
在此处查看更多信息: http://blog.roboblob.com/2012/09/19/dot-net-gotcha-nr1-list-versus-collection-constructor/
答案 42 :(得分:5)
到目前为止,我最糟糕的一个,我今天才知道......如果你覆盖object.Equals(object obj),你可以发现:
((MyObject)obj).Equals(this);
与以下行为不同:
((MyObject)obj) == this;
一个人会调用你的覆盖功能,另一个人不会。
答案 43 :(得分:5)
必须按顺序添加Oracle参数
这是Oracle的参数化查询的ODP .Net实现中的一个主要问题。
向查询添加参数时,默认行为是参数名称忽略,并按照添加顺序使用这些值。
解决方案是将BindByName
对象的OracleCommand
属性设置为true
- 默认为false
...这是定性的(如果不是非常定量)比如拥有一个名为DropDatabaseOnQueryExecution
的属性,其默认值为true
。
They call it a feature; I call it a pit in the public domain
有关详细信息,请参阅here。
答案 44 :(得分: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
成员。它本应该检查所有枚举成员,如果一个成员在交换机案例中不存在,那么这样的错误就会有意义,但是现在我应该添加一个Default
案例,这个案例是多余的,并且永远不会被代码触及。
编辑:
经过对此问题的更多研究后,我来到Eric Lippert's nice written and useful post,但它仍然有点奇怪。你同意吗?
答案 45 :(得分:4)
递归属性问题
我认为并非特定于C#,而且我确信我已经在其他地方看到了它(this提醒我的问题)
它可以有两种方式,但最终结果是相同的:
在覆盖属性时忘记引用base.
:
public override bool IsRecursive
{
get { return IsRecursive; }
set { IsRecursive = value; }
}
从自动属性更改为支持属性,但并不完全一直:
public bool IsRecursive
{
get { return IsRecursive; }
set { IsRecursive = value; }
}
答案 46 :(得分:3)
发生在我身上的最糟糕的事情是webBrowser documentText问题:
http://geekswithblogs.net/paulwhitblog/archive/2005/12/12/62961.aspx#107062
AllowNavigation解决方案适用于Windows窗体...
但在紧凑的框架中,该属性不存在......
...到目前为止,我找到的唯一解决方法是重建浏览器控件:
但是这样做,你需要手头处理浏览器历史......:P
答案 47 :(得分:3)
答案 48 :(得分:3)
答案 49 :(得分:2)
LINQ to SQL和一对多关系
这是一个让我咬了几次的可爱的人,MS把它留给了自己的一个开发者,把它放在her blog中。我不能比她做得更好,所以看看那里。
答案 50 :(得分:2)
相关对象和外键不同步
Microsoft have admitted to this bug
我有一个班级Thing
,其FK为Category
。类别与Thing没有定义的关系,以免污染接口。
var thing = CreateThing(); // does stuff to create a thing
var category = GetCategoryByID(123); // loads the Category with ID 123
thing.Category = category;
Console.WriteLine("Category ID: {0}", thing.CategoryID);
输出:
Category ID: 0
类似地:
var thing = CreateThing();
thing.CategoryID = 123;
Console.WriteLine("Category name: {0}", order.Category.Name);
抛出NullReferenceException
。相关对象Category
未加载ID为123的类别记录。
但是,在向DB提交更改后,这些值会同步。但在您访问数据库之前,FK值和相关对象功能几乎是独立的!
(有趣的是,当没有定义子关系时,似乎没有将FK值与相关对象同步,即类别没有“物品”属性。但是当你设置了它时,“按需加载” FK值永远不会起作用。)
<强> GOTCHA!强>
答案 51 :(得分:1)
不是最糟糕的,但尚未提出的。即使只使用一个返回值,也可以多次调用作为参数传递给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
答案 52 :(得分:1)
将容量传递给List<int>
而不是使用收集初始化程序。
var thisOnePasses = new List<int> {2}; // collection initializer
var thisOneFails = new List<int> (2); // oops, use capacity by mistake #gotcha#
thisOnePasses.Count.Should().Be(1);
thisOnePasses.First().Should().Be(2);
thisOneFails.Count.Should().Be(1); // it's zero
thisOneFails.First().Should().Be(2); // Sequence contains no elements...
答案 53 :(得分:1)
有时堆栈跟踪中的行号与源代码中的行号不匹配。这可能是由于用于优化的简单(单行)函数的内联而发生的。对于使用日志进行调试的人来说,这是一个严重的混淆源。
编辑:示例:有时您会在堆栈跟踪中看到一个空引用异常,它指向一行代码,绝对没有空引用异常,就像一个简单的整数赋值。
答案 54 :(得分:1)
我一直认为value
类型始终位于stack
上的reference
和heap
类型上。
好吧不那么。当我最近在SO上看到this question时(可以说错误地回答)我开始知道情况并非如此。
当Jon Skeet回答(提及Eric Lippert's Blog post)时,其神话。
相当重要的链接:
答案 55 :(得分:1)
LinqToSQL和空集聚合
请参阅this question。
如果您有运行聚合的LinqToSql查询 - 如果您的结果集为空,则Linq无法确定数据类型是什么,即使它已被声明。
e.g。假设您有一个包含字段Claim
的表Amount
,其在LinqToSql中的类型为decimal
。
var sum = Claims.Where(c => c.ID < 0).Sum(c => c.Amount);
显然没有声明的ID小于零,所以你期望看到sum = null,对吧? 错误!您得到InvalidOperationException
,因为Linq查询底层的SQL查询没有数据类型。你必须明确地告诉Linq它是小数!因此:
var sum = Claims.Where(c => c.ID < 0).Sum(c => (decimal?)c.Amount);
这真是愚蠢,IMO是微软的设计缺陷。
<强> GOTCHA!强>
答案 56 :(得分:1)
以下内容不会在.Net中捕获异常。相反,它会导致StackOverflow异常。
private void button1_Click( object sender, EventArgs e ) {
try {
CallMe(234);
} catch (Exception ex) {
label1.Text = ex.Message.ToString();
}
}
private void CallMe( Int32 x ) {
CallMe(x);
}
对于评论者(和赞成票):
堆栈溢出是非常罕见的。但是,如果出现这种情况,您将无法捕获异常,并可能花费几个小时试图找到问题的确切位置。如果SO出现在很少使用的逻辑路径中,可能会更复杂,尤其是在您可能不知道启动问题的确切条件的Web应用程序上。
这与此问题的接受答案(https://stackoverflow.com/a/241194/2424)的情况完全相同。该答案的属性getter基本上与上面的代码完全相同,并且没有堆栈跟踪崩溃。
答案 57 :(得分:0)
Linq2SQL:不支持接口成员[...]的映射。
如果对实现接口的对象执行Linq2Sql查询,则会出现非常奇怪的行为。假设您有一个实现接口MyClass
的类IHasDescription
,因此:
public interface IHasDescription {
string Description { get; set; }
}
public partial class MyClass : IHasDescription { }
(MyClass
的另一半是Linq2Sql生成的类,包括属性Description
。)
现在你编写一些代码(通常这种情况发生在通用方法中):
public static T GetByDescription<T>(System.Data.Linq.Table<T> table, string desc)
where T : class, IHasDescription {
return table.Where(t => t.Description == desc).FirstOrDefault();
}
编译正常 - 但是你得到一个运行时错误:
NotSupportedException: The mapping of interface member IHasDescription.Description is not supported.
现在whaddaya那样做了吗?嗯,显而易见:只需将==
更改为.Equals()
,即可:
return table.Where(t => t.Description.Equals(desc)).FirstOrDefault();
现在一切正常!
请参阅here。
答案 58 :(得分:0)
使用批量大小的平方LinqToSql批次变慢
Here's the question(和answer)我探讨了这个问题。
简而言之,如果在调用DataContext.SubmitChanges()
之前尝试在内存中构建太多对象,则会以几何速率开始出现迟缓。我没有确认100%是这种情况,但在我看来,对DataContext.GetChangeSet()
的调用导致数据上下文对2个项目的每个组合执行等价评估(.Equals()
)更改集,可能是为了确保它不是双重插入或导致其他并发问题。问题是,如果您的批次非常大,则比较次数会与 n 的平方成比例增加,即(n ^ 2 + n)/ 2 。内存中的1000个项目意味着超过500,000个比较......这可能需要很长时间才能获得heckuva。
为了避免这种情况,您必须确保对于您预期大量项目的任何批次,您在事务边界内执行整个操作,在创建时保存每个项目,而不是在最后保存一个大项目
答案 59 :(得分:0)
mystring.Replace("x","y")
虽然它看起来应该对字符串进行替换,但是它实际上会返回一个新的字符串,其中包含替换而不更改它所调用的字符串。你需要记住字符串是不可变的。
答案 60 :(得分:-1)
一些代码:
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 - 检查整数,直到找到“正确”的整数。