384 Stimmen

Was ist der schlimmste Fehler in C# oder .NET?

Ich habe kürzlich mit einem DateTime Objekt, und schrieb etwas wie dieses:

DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?

Die Intellisense-Dokumentation für AddDays() sagt, dass es einen Tag zum Datum hinzufügt, was nicht der Fall ist - es devuelve ein Datum mit einem hinzugefügten Tag, also müssen Sie es so schreiben:

DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date

Dies hat mich schon einige Male gebissen, also dachte ich, es wäre nützlich, die schlimmsten C#-Fehler zu katalogisieren.

158 Stimmen

Return DateTime.Now.AddDays(1);

24 Stimmen

Soweit ich weiß, sind die eingebauten Werttypen alle unveränderlich, zumindest insofern, als jede Methode, die mit dem Typ verbunden ist, ein neues Element zurückgibt, anstatt das vorhandene Element zu verändern. Zumindest fällt mir spontan kein Typ ein, der dies nicht tut: alles schön und konsistent.

1 Stimmen

Community-Wiki, so viel Spam in SO jetzt. Wenn Fragen subjektiv sind (keine endgültige Antwort), sollte es Community Wiki sein.

81voto

Timothy Walters Punkte 16633

Speicherverluste, weil Sie Ereignisse nicht abgehängt haben.

Das hat sogar einige erfahrene Entwickler, die ich kenne, überrascht.

Stellen Sie sich ein WPF-Formular mit vielen Dingen darin vor, und irgendwo da drin abonnieren Sie ein Ereignis. Wenn Sie nicht abbestellen, dann wird das gesamte Formular im Speicher gehalten, nachdem es geschlossen und de-referenziert wurde.

Ich glaube, das Problem, das ich sah, war die Erstellung eines DispatchTimer in der WPF-Form und abonnieren Sie das Tick-Ereignis, wenn Sie nicht tun, ein -= auf den Timer Ihre Form leckt Speicher!

In diesem Beispiel sollte Ihr Teardown-Code wie folgt aussehen

timer.Tick -= TimerTickEventHandler;

Dies ist besonders knifflig, da Sie die Instanz des DispatchTimer innerhalb des WPF-Formulars erstellt, so dass Sie denken würden, dass es ein interner Verweis durch den Garbage Collection-Prozess behandelt werden würde... leider der DispatchTimer verwendet eine statische interne Liste von Abonnements und Dienste-Anforderungen auf dem UI-Thread, so dass der Verweis von der statischen Klasse "gehört".

63voto

jdehaan Punkte 19398

Vielleicht nicht wirklich ein Problem, weil das Verhalten klar in MSDN beschrieben ist, aber es hat mir einmal das Genick gebrochen, weil ich es ziemlich kontra-intuitiv fand:

Image image = System.Drawing.Image.FromFile("nice.pic");

Dieser Mann verlässt die "nice.pic" Datei gesperrt, bis das Bild entsorgt wird. Als ich damit konfrontiert wurde, dachte ich, es wäre schön, Icons im Handumdrehen zu laden, und wusste (zunächst) nicht, dass ich am Ende Dutzende von offenen und gesperrten Dateien hatte! Image merkt sich, woher es die Datei geladen hat...

Wie lässt sich das Problem lösen? Ich dachte, ein One-Liner würde die Aufgabe erfüllen. Ich erwartete einen zusätzlichen Parameter für FromFile() aber ich hatte keine, also habe ich das geschrieben...

using (Stream fs = new FileStream("nice.pic", FileMode.Open, FileAccess.Read))
{
    image = System.Drawing.Image.FromStream(fs);
}

51voto

Jimmy Punkte 85199

Überladene == Operatoren und nicht typisierte Container (Arraylisten, Datensätze usw.):

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

Lösungen?

  • immer verwenden string.Equals(a, b) wenn Sie Zeichenketten vergleichen

  • mit Generika wie List<string> um sicherzustellen, dass beide Operanden Zeichenketten sind.

51voto

Erik van Brakel Punkte 22454

Wenn man ASP.NET mitzählt, würde ich sagen, dass der Lebenszyklus von Webforms für mich ein ziemlich großes Problem darstellt. Ich habe unzählige Stunden damit verbracht, schlecht geschriebenen Webforms-Code zu debuggen, nur weil viele Entwickler einfach nicht wirklich verstehen, wann welcher Event-Handler zu verwenden ist (mich eingeschlossen, leider).

50voto

Nicolas Dorier Punkte 7327
[Serializable]
class Hello
{
    readonly object accountsLock = new object();
}

//Do stuff to deserialize Hello with BinaryFormatter
//and now... accountsLock == null ;)

Die Moral von der Geschichte: Feldinitialisierer werden nicht ausgeführt, wenn ein Objekt deserialisiert wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X