Erzwingen des erforderlichen Funktionsaufrufs

8

Ich habe eine "Status" -Klasse in C #, die folgendermaßen verwendet wird:

%Vor%

Sie bekommen die Idee. Alle Aufrufer von MyFunction sollten den zurückgegebenen Status überprüfen:

%Vor%

Lazy Caller können jedoch den Status ignorieren.

%Vor%

oder

%Vor%

Ist es möglich, dies unmöglich zu machen? z.B. eine Wurfausnahme

Allgemein : Ist es möglich, eine C # -Klasse zu schreiben, auf der Sie eine bestimmte Funktion aufrufen können?

In der C ++ - Version der Status-Klasse kann ich einen Test auf einige private bolSchecks im Destruktor schreiben und ein paar Klingeln läuten lassen, wenn jemand diese Instanz nicht überprüft.

Was ist die äquivalente Option in C #? Ich habe irgendwo gelesen, dass "Sie keinen Destruktor in Ihrer C # -Klasse wollen"

Ist die Dispose-Methode der IDisposable-Schnittstelle eine Option?

In diesem Fall gibt es keine nicht verwalteten Ressourcen zum Freigeben. Darüber hinaus wird nicht bestimmt, wenn der GC das Objekt entsorgen wird. Wenn es schließlich entsorgt wird, ist es immer noch möglich zu wissen, wo und wann Sie diese spezifische Statusinstanz ignoriert haben? Das "using" -Schlüsselwort hilft zwar, aber auch hier ist für faule Anrufer nicht erforderlich .

    
jan 21.08.2008, 09:57
quelle

11 Antworten

2

Ich bin ziemlich sicher, dass Sie den gewünschten Effekt nicht als Rückgabewert einer Methode erhalten können. C # kann einige der Dinge, die C ++ kann, nicht tun. Eine etwas hässliche Art, einen ähnlichen Effekt zu erzielen, ist jedoch folgender:

%Vor%

Im sehr einfachen Beispiel erhalten Sie eine Instanz von Toy, indem Sie Parent.RequestToy, aufrufen und einen Delegaten übergeben . Anstatt das Spielzeug zurückzugeben, ruft die Methode sofort den Delegierten mit dem Spielzeug auf, der PutAway aufrufen muss, bevor es zurückkehrt, oder die RequestToy-Methode löst eine Ausnahme aus. Ich mache keinen Anspruch auf die Weisheit, diese Technik zu verwenden - in der Tat ist eine Ausnahme bei allen "etwas schief gelaufenen Beispielen" mit ziemlicher Sicherheit eine bessere Wette - aber ich denke, es kommt so nah wie möglich an Ihre ursprüngliche Anfrage heran.

    
Weeble 21.08.2008, 13:17
quelle
10

Ich weiß, dass dies Ihre Frage nicht direkt beantwortet, aber wenn "etwas schief gelaufen ist" innerhalb Ihrer Funktion (unerwartete Umstände), sollten Sie eine Ausnahme auslösen, anstatt Status-Returncodes zu verwenden.

Überlassen Sie es dann dem Aufrufer, diese Ausnahme abzufangen und zu behandeln, oder lassen Sie sie weiterlaufen, wenn der Aufrufer die Situation nicht verarbeiten kann.

Die ausgelöste Ausnahme könnte benutzerdefinierten Typs sein, wenn dies angemessen ist.

Für erwartete alternative Ergebnisse stimme ich dem Vorschlag von @Jon Limjap zu. Ich mag einen Bool-Return-Typ und setze den Methodennamen mit "Try" voran, a la:

%Vor%     
Ian Nelson 21.08.2008 10:02
quelle
7

Wenn Sie wirklich möchten, dass der Benutzer das Ergebnis von MyFunction abruft, möchten Sie es möglicherweise stattdessen löschen und eine out- oder ref-Variable verwenden, z. B.

%Vor%

Es sieht vielleicht hässlich aus, aber es stellt zumindest sicher, dass eine Variable an die Funktion übergeben wird, die das Ergebnis aufnimmt, das sie zum Aufnehmen benötigt.

@Ian,

Das Problem mit Ausnahmen besteht darin, dass Sie zu viel Systemressourcen für die Ausnahme ausgeben, wenn es etwas zu häufig passiert. Eine Ausnahme sollte wirklich für Ausnahme Fehler, nicht vollständig erwartete Nachrichten verwendet werden.

    
Jon Limjap 21.08.2008 10:28
quelle
3

Auch System.Net.WebRequest löst eine Ausnahme aus, wenn der zurückgegebene HTTP-Statuscode ein Fehlercode ist. Der typische Weg, um damit umzugehen, ist es, einen Versuch / Fang um ihn herum zu wickeln. Sie können den Statuscode im Catch-Block weiterhin ignorieren.

Sie könnten jedoch einen Parameter von Action & lt; Status & gt; so dass der Anrufer gezwungen wird, eine Rückruffunktion zu übergeben, die einen Status akzeptiert und dann überprüft, ob sie ihn angerufen haben.

%Vor%

Wenn Sie besorgt sind, dass sie IsOK () aufrufen, ohne etwas zu tun, verwenden Sie Expression & lt; Func & lt; Status, bool & gt; & gt; Stattdessen und dann können Sie das Lambda analysieren, um zu sehen, was sie mit dem Status tun:

%Vor%

Oder verzichten Sie vollständig auf die Statusklasse und sorgen Sie dafür, dass sie in einem Delegat für den Erfolg und in einem anderen für einen Fehler übergeben werden:

%Vor%     
Mark Cidade 21.08.2008 10:23
quelle
1

Die Verwendung von Status als Rückgabewert erinnert mich an die "alten Tage" der C-Programmierung, als Sie eine Ganzzahl unter 0 zurückgaben, wenn etwas nicht funktionierte.

Wäre es nicht besser, wenn Sie eine Ausnahme auslösen, wenn (wie Sie es nennen) etwas schief gelaufen ist ? Wenn einige "Lazy Code" Ihre Ausnahme nicht abfangen, werden Sie es sicher wissen.

    
Auron 21.08.2008 10:11
quelle
1

Anstatt jemanden dazu zu zwingen, den Status zu überprüfen, sollten Sie davon ausgehen, dass der Programmierer sich der Gefahr bewusst ist, dies nicht zu tun, und einen Grund hat, diesen Weg einzuschlagen. Sie wissen nicht, wie die Funktion in der Zukunft verwendet wird, und eine solche Einschränkung beschränkt nur die Möglichkeiten.

    
kemiller2002 21.08.2008 11:51
quelle
0

Das wäre sicher schön, wenn der Compiler das überprüft und nicht durch einen Ausdruck. : / Ich sehe jedoch keine Möglichkeit, das zu tun ...

    
fulmicoton 21.08.2008 10:07
quelle
0

Sie können eine Ausnahme auslösen durch:

%Vor%

Die obige Ausnahme ist vollständig an Ihre Anforderungen anpassbar.

Eine Sache würde ich sagen: Ich würde es dem Anrufer überlassen, den Rückgabecode zu überprüfen, es liegt in ihrer Verantwortung, dass Sie nur die Mittel und die Schnittstelle bereitstellen. Außerdem ist es viel effizienter, Rückgabecodes zu verwenden und den Status mit einer if-Anweisung anstatt mit Ausnahmen zu überprüfen. Wenn es sich wirklich um einen außergewöhnlichen Umstand handelt, dann wegwerfen ... aber sagen Sie, wenn Sie ein Gerät nicht öffnen konnten, dann wäre es vielleicht vernünftiger, mit dem Rückkehrcode zu bleiben.

>     
TK. 21.08.2008 10:02
quelle
0

@Paul Sie könnten es zur Kompilierungszeit mit Erweiterbares C # .

    
Mark Cidade 21.08.2008 10:42
quelle
0

GCC hat ein warn_unused_result Attribut, das für diese Art von Dingen ideal ist. Vielleicht haben die Microsoft Compiler ähnliches.

    
pauldoo 21.08.2008 10:31
quelle
0

Ein Muster, das manchmal hilfreich sein kann, wenn das Objekt, an das der Code Anfragen abgibt, nur von einem einzigen Thread verwendet wird, ist, dass das Objekt einen Fehlerstatus behält und dass ein Objekt fehlschlägt, wenn ein Vorgang fehlschlägt unbrauchbar, bis der Fehlerzustand zurückgesetzt wird (zukünftige Anforderungen sollten sofort fehlschlagen, vorzugsweise durch Auslösen einer sofortigen Ausnahme, die Informationen über den vorherigen Fehler und die neue Anforderung enthält). In Fällen, in denen der aufrufende Code ein Problem vorwegnimmt, kann dies dem aufrufenden Code ermöglichen, das Problem sauberer zu behandeln, als wenn eine Ausnahme ausgelöst würde. Probleme, die vom aufrufenden Code nicht ignoriert werden, lösen im Allgemeinen eine Ausnahme aus, sobald sie auftreten.

(*) Wenn auf eine Ressource von mehreren Threads zugegriffen wird, erstellen Sie ein Wrapper-Objekt für jeden Thread, und die Anforderungen jedes Threads durchlaufen einen eigenen Wrapper.

Dieses Muster ist auch in Kontexten anwendbar, in denen Ausnahmen nicht möglich sind, und kann in solchen Fällen manchmal sehr praktisch sein. Im Allgemeinen ist jedoch eine gewisse Variation des try / do-Musters normalerweise besser. Lassen Sie Methoden eine Exception auslösen, wenn der Aufrufer explizit (durch Verwendung einer TryXX -Methode) angibt, dass Fehler erwartet werden. Wenn Anrufer sagen, dass Fehler erwartet werden, aber nicht mit ihnen umgehen, ist das ihr Problem. Man könnte das Try / Do mit einer zweiten Schutzschicht kombinieren, indem man das obige Schema verwendet, aber ich bin mir nicht sicher, ob es die Kosten wert wäre.

    
supercat 02.10.2014 21:38
quelle