Ich betrachte dies als Missbrauch der using-Anweisung. Mir ist bewusst, dass ich in dieser Position in der Minderheit bin.
Ich betrachte dies aus drei Gründen als Missbrauch.
Erstens, weil ich davon ausgehe, dass "using" verwendet wird, um eine Ressource zu verwenden und zu entsorgen, wenn Sie damit fertig sind . Das Ändern des Programmstatus verwendet keine Ressource und das Zurücksetzen ändert nichts. Daher ist das "Verwenden" zum Mutieren und Wiederherstellen des Zustands ein Missbrauch. Der Code ist für den Gelegenheitsleser irreführend.
Zweitens, weil ich erwarte, dass "Verwenden" aus Höflichkeit und nicht aus Notwendigkeit verwendet wird . Der Grund, warum Sie "using" verwenden, um eine Datei zu entsorgen, wenn Sie damit fertig sind, liegt nicht darin, dass dies erforderlich ist , sondern darin, dass es höflich ist - möglicherweise wartet jemand anderes darauf, diese Datei zu verwenden, und sagt "erledigt" jetzt "ist die moralisch korrekte Sache zu tun. Ich gehe davon aus, dass ich in der Lage sein sollte, eine "Verwendung" umzugestalten, damit die verwendete Ressource länger aufbewahrt und später entsorgt wird, und dass die einzige Auswirkung darin besteht, andere Prozesse geringfügig zu stören . Ein "using" -Block, der semantische Auswirkungen auf den Programmstatus hat ist missbräuchlich, weil es eine wichtige, erforderliche Mutation des Programmzustands in einem Konstrukt verbirgt, das so aussieht, als ob es der Bequemlichkeit und Höflichkeit dient, nicht der Notwendigkeit.
Und drittens werden die Aktionen Ihres Programms durch seinen Status bestimmt. Die Notwendigkeit einer sorgfältigen Manipulation des Staates ist genau der Grund, warum wir dieses Gespräch überhaupt führen. Lassen Sie uns überlegen, wie wir Ihr ursprüngliches Programm analysieren könnten.
Wenn Sie dies zu einer Codeüberprüfung in meinem Büro bringen würden, würde ich als erstes die Frage stellen: "Ist es wirklich richtig, das Frobble zu sperren, wenn eine Ausnahme ausgelöst wird?" Aus Ihrem Programm geht eindeutig hervor, dass dieses Ding das Frobble aggressiv wieder sperrt, egal was passiert. Ist das richtig? Eine Ausnahme wurde ausgelöst. Das Programm befindet sich in einem unbekannten Zustand. Wir wissen nicht, ob Foo, Fiddle oder Bar geworfen haben, warum sie geworfen haben oder welche Mutationen sie in einem anderen Zustand durchgeführt haben, der nicht aufgeräumt wurde. Können Sie mich davon überzeugen , dass es in dieser schrecklichen Situation immer das Richtige ist, erneut zu sperren?
Vielleicht ist es das, vielleicht ist es das nicht. Mein Punkt ist, dass der Code-Prüfer mit dem Code, wie er ursprünglich geschrieben wurde, die Frage stellen kann . Mit dem Code, der "using" verwendet, weiß ich nicht, ob ich die Frage stellen soll. Ich gehe davon aus, dass der "using" -Block eine Ressource zuweist, sie für eine Weile verwendet und höflich darüber verfügt, wenn dies erledigt ist, und nicht, dass die schließende Klammer des "using" -Blocks meinen Programmstatus unter außergewöhnlichen Umständen mutiert, wenn beliebig viele Die Konsistenzbedingungen des Programmstatus wurden verletzt.
Die Verwendung des "using" -Blocks für einen semantischen Effekt macht dieses Programmfragment:
}
äußerst bedeutungsvoll. Wenn ich mir diese einzelne enge Zahnspange ansehe, denke ich nicht sofort, "dass diese Zahnspange Nebenwirkungen hat, die weitreichende Auswirkungen auf den globalen Status meines Programms haben". Aber wenn Sie "Verwenden" so missbrauchen, geschieht dies plötzlich.
Das zweite, was ich fragen würde, wenn ich Ihren Originalcode sehen würde, ist "Was passiert, wenn eine Ausnahme nach dem Entsperren ausgelöst wird, aber bevor der Versuch eingegeben wird?" Wenn Sie eine nicht optimierte Assembly ausführen, hat der Compiler möglicherweise vor dem Versuch eine No-Op-Anweisung eingefügt, und es ist möglich, dass beim No-Op eine Thread-Abbruch-Ausnahme auftritt. Dies ist selten, aber im wirklichen Leben, insbesondere auf Webservern. In diesem Fall erfolgt die Entsperrung, die Sperre jedoch nie, da die Ausnahme vor dem Versuch ausgelöst wurde. Es ist durchaus möglich, dass dieser Code für dieses Problem anfällig ist und tatsächlich geschrieben werden sollte
bool needsLock = false;
try
{
// must be carefully written so that needsLock is set
// if and only if the unlock happened:
this.Frobble.AtomicUnlock(ref needsLock);
blah blah blah
}
finally
{
if (needsLock) this.Frobble.Lock();
}
Wieder vielleicht, vielleicht auch nicht, aber ich weiß, dass ich die Frage stellen muss . Bei der "using" -Version tritt das gleiche Problem auf: Eine Thread-Abbruch-Ausnahme kann ausgelöst werden, nachdem das Frobble gesperrt wurde, aber bevor der mit der Verwendung verknüpfte try-geschützte Bereich eingegeben wird. Aber mit der "using" -Version gehe ich davon aus, dass dies ein "na und?" Ist. Lage. Es ist bedauerlich, wenn das passiert, aber ich gehe davon aus, dass das "Verwenden" nur dazu da ist, höflich zu sein, nicht um den lebenswichtigen Programmzustand zu mutieren. Ich gehe davon aus, dass der Garbage Collector diese Ressource schließlich durch Ausführen des Finalizers bereinigt, wenn eine schreckliche Ausnahme für den Thread-Abbruch genau zum falschen Zeitpunkt auftritt.