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.

16voto

softveda Punkte 10552

Heute habe ich einen Fehler behoben, der lange Zeit verschwunden war. Der Fehler war in einer generischen Klasse, die in einem Multi-Thread-Szenario verwendet wurde und ein statisches int-Feld wurde verwendet, um eine sperrfreie Synchronisation mit Interlocked zu ermöglichen. Der Fehler wurde dadurch verursacht, dass jede Instanziierung der generischen Klasse für einen Typ seine eigene Statik hat. So bekam jeder Thread sein eigenes statisches Feld und es wurde nicht wie vorgesehen eine Sperre verwendet.

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);
    }
}

Dies druckt 5 10 5

16voto

Stefan Steinegger Punkte 62197

Veranstaltungen

Ich habe nie verstanden, warum Ereignisse ein Sprachmerkmal sind. Sie sind kompliziert zu benutzen: man muss vor dem Aufruf auf null prüfen, man muss sich (selbst) abmelden, man kann nicht herausfinden, wer angemeldet ist (z.B.: habe ich mich angemeldet?). Warum ist ein Ereignis nicht einfach eine Klasse in der Bibliothek? Im Grunde genommen eine spezialisierte List<delegate> ?

15voto

DevDave Punkte 6491

Ich habe gerade einen seltsamen Fall gefunden, bei dem ich eine Weile im Debug-Modus festsaß:

Sie können null für einen nullable int inkrementieren, ohne eine Excecption auszulösen, und der Wert bleibt null.

int? i = null;
i++; // I would have expected an exception but runs fine and stays as null

14voto

chakrit Punkte 59834

Aufzählungszeichen können mehr als einmal ausgewertet werden

Es wird Sie beißen, wenn Sie eine lazily-enumerated enumerable haben und Sie iterieren über sie zweimal und erhalten unterschiedliche Ergebnisse. (oder Sie erhalten die gleichen Ergebnisse, aber es wird unnötigerweise zweimal ausgeführt)

Als ich zum Beispiel einen bestimmten Test schrieb, brauchte ich ein paar temporäre Dateien, um die Logik zu testen:

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);

Stellen Sie sich meine Überraschung vor, als File.Delete(file) wirft FileNotFound !!

Was hier passiert ist, dass die files Aufzählung wurde iteriert zweimal (die Ergebnisse der ersten Iteration sind einfach no gemerkt) und bei jeder neuen Iteration würden Sie erneut Path.GetTempFilename() so dass Sie einen anderen Satz von temporären Dateinamen erhalten.

Die Lösung besteht natürlich darin, den Wert eager-enumerate mit Hilfe von ToArray() ou ToList() :

var files = Enumerable.Range(0, 5)
    .Select(i => Path.GetTempFileName())
    .ToArray();

Dies ist noch beängstigender, wenn Sie etwas mit mehreren Threads machen, wie z. B.:

foreach (var file in files)
    content = content + File.ReadAllText(file);

und Sie finden heraus content.Length nach all den Schreibvorgängen immer noch 0 ist!! Sie fangen dann an, rigoros zu überprüfen, dass Sie keine Race Condition haben, wenn.... nach einer vergeudeten Stunde... Sie herausgefunden haben, dass es nur diese winzige kleine Enumerable gotcha Sache ist, die Sie vergessen haben....

11voto

Trident D'Gao Punkte 17318

Das ist ein Super-Gotcha, mit dessen Fehlersuche ich 2 Tage verschwendet habe. Es hat keine Ausnahmen geworfen, es stürzte nur den Webserver mit einigen Seltsame Fehlermeldungen . Ich konnte das Problem in DEV nicht reproduzieren. Außerdem haben die Experimente mit den Projekt-Build-Einstellungen irgendwie dazu geführt, dass es im PROD verschwand, dann kam es zurück. Schließlich habe ich es.

Sagen Sie mir, ob Sie ein Problem in dem folgenden Codestück sehen:

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);
    }
}

Wenn Sie also Wert auf Ihre geistige Gesundheit legen:

!!! Niemals irgendeine Logik in Trace-Methoden einbauen !!!

Der Code muss so ausgesehen haben:

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);
    }
}

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