Sollte der Service eine Ausnahme auslösen oder zurückkehren, wenn keine Elemente zum Löschen angegeben wurden

12

Ich habe einen Code, der wie folgt dargestellt werden kann:

public class ItemService {

    public void DeleteItems(IEnumerable<Item> items)
    {
        // Save us from possible NullReferenceException below.
        if(items == null)
            return;

        foreach(var item in items)
        {
            // For the purpose of this example, lets say I have to iterate over them.
            // Go to database and delete them.
        }
    }
}

Jetzt frage ich mich, ob dies der richtige Ansatz ist oder ob ich eine Ausnahme machen soll. Ich kann Ausnahmen vermeiden, da das Zurückgeben dasselbe wäre, als würde eine leere Sammlung durchlaufen, was bedeutet, dass ohnehin kein wichtiger Code ausgeführt wird, aber auf der anderen Seite verstecke ich möglicherweise Probleme irgendwo im Code, denn warum sollte jemand anrufen wollen DeleteItemsmit nullParameter? Dies kann darauf hindeuten, dass an einer anderen Stelle im Code ein Problem vorliegt.

Dies ist ein Problem, das ich normalerweise bei Methoden in Diensten habe, da die meisten von ihnen etwas tun und kein Ergebnis zurückgeben. Wenn also jemand ungültige Informationen übergibt, hat der Dienst nichts zu tun, sodass er zurückgibt.

FCin
quelle
2
Dies ist nur meine persönliche Meinung, aber ich fand es immer am sinnvollsten, dass eine Methode eine Ausnahme auslöst, wenn sie etwas ungewolltes (außergewöhnliches) tut. In Ihrem Fall würde ich eine InvalidOperationException auslösen, wenn jemand versucht, null / 0-Elemente zu löschen.
Falgantil
1
@gnat Meine Frage bezieht sich speziell auf Dienste, auf deren Verwendung und Zweck. Dieses "Duplikat" spricht nur die allgemeinen Fälle an und die Hauptantwort widerspricht sich sogar im Kontext meiner genauen Methode.
FC
2
Ist es möglich, dass die Aufzählung leer anstelle von null ist? Würden Sie das anders behandeln?
JAD
13
@ Falgantil Ich kann sehen, dass null eine Ausnahme wert ist, aber ich finde es absurd, eine Ausnahme auf eine leere Liste zu werfen.
Kevin

Antworten:

58

Das sind zwei verschiedene Fragen.

Solltest du akzeptieren null? Das hängt von Ihrer allgemeinen Richtlinie nullin der Codebasis ab. Meiner Meinung nach nullist es eine sehr gute Praxis, überall zu verbieten , außer wo dies ausdrücklich dokumentiert ist, aber es ist noch besser, sich an die Konvention zu halten, die Ihre Codebasis bereits hat.

Sollten Sie die leere Sammlung akzeptieren? Meiner Meinung nach: JA, absolut. Es ist viel mühsamer, alle Aufrufer auf nicht leere Sammlungen zu beschränken, als das mathematisch Richtige zu tun - auch wenn es einige Entwickler überrascht, die mit dem Konzept von Null nicht einverstanden sind.

Kilian Foth
quelle
9
In jedem Fall, wenn Sie werfen wollen, gibt es nicht allzu viel Nutzen beim Werfen, AhaINoticedYouPassingInNullExceptionwenn die Laufzeit Ihnen bereits die Möglichkeit bietet, NullReferenceExceptionfür Sie zu werfen , ohne dass Sie Code schreiben müssen. Es gibt einige Hilfsprogramme (z. B. Ihr Code-Coverage-Tool teilt Ihnen mit, ob Sie im ersten Fall einen Unit-Test für die Übergabe von Null durchgeführt haben, im zweiten Fall jedoch nicht), aber keine der Ausnahmen sollte bei jedem Aufruf des Dienstes ausprobiert / abgefangen werden. weil es normalerweise ein Programmiererfehler ist.
Steve Jessop
2
... Sie sollten nur dann sofort Ausnahmen abfangen, die aufgrund skizzenhafter Parameter ausgelöst wurden, wenn Sie wissen, dass das, was Sie übergeben, in einem erwarteten Fall null ist und Sie möchten, dass die aufgerufene Funktion es für Sie validiert. Wie Kilian in der Antwort sagt, könnte es Ihre allgemeine Regel sein, Null überall dort zu verbieten, wo dies nicht ausdrücklich erlaubt ist. Dann würden Sie nicht fangen NullReferenceExceptionoder AhaINoticedYouPassingInNullExceptionirgendwo anders auf hohem Niveau , Disaster-Recovery - Code. Und dieser Ausnahmehandler sollte wahrscheinlich einen Fehlerbericht erstellen :-)
Steve Jessop
2
@FCin: Ihr Schnittstellendesign sollte mit dem übereinstimmen, was Benutzer tatsächlich für den Dienst benötigen. Wenn also jeder Anrufer versuchen / fangen will, sollte entweder diese Methode oder eine andere Bequemlichkeitsmethode auf Null prüfen und diese ignorieren, da dies von Ihrer Öffentlichkeit gefordert wird. Wie Kilian jedoch sagt, ist es in der Regel besser, die Weitergabe von Nullen als Programmierfehler zu behandeln und nicht an jedem Anrufstandort fortzufahren. Was ist nullim Übrigen , wenn der Dienst, für den diese Methode aufgerufen wird, lautet : Enthalten die Steuerungen Boilerplate, um auch in diesem Fall zu erfassen und fortzufahren?
Steve Jessop
2
... wenn ja, dann scheint es so, als würde die Codebasis fehlende Komponenten konsequent als eine erwartete Bedingung behandeln, die Sie auf niedriger Ebene handhaben und fortsetzen sollten. Sie können sich vernünftigerweise fragen: "Wem obliegt es, einen Dienst und eine Aufzählung bereitzustellen, damit diese Operation durchgeführt werden kann?". Wenn die Antwort "Jemand" lautet, überprüft Ihre Funktion die Voraussetzungen , und das Ergebnis einer fehlgeschlagenen Voraussetzung ist normalerweise eine Ausnahme, die auf hoher Ebene und nicht bei jedem Anruf abgefangen wird. Wenn das für die Operation erforderliche Material wirklich optional ist, behandelt Ihre Funktion einen erwarteten Anwendungsfall .
Steve Jessop
2
Das explizite Auslösen von a ArgumentNullExceptionist dem Ermöglichen des Auslösens eines internen Codes überlegen. Wenn Sie NullReferenceExceptionlediglich die Ausnahmemeldung betrachten, ist es offensichtlich, dass es sich eher um einen Eingabefehler als um einen logischen Fehler im Methodenkörper an der Auslösestelle handelt Es ist wahrscheinlicher, dass Sie andere Daten in einem gültigen Zustand belassen haben, anstatt sie später teilweise von einer unerwarteten Null zu mutieren.
Miral
9

Nullwert

Halten Sie sich, wie @KilianFoth bereits sagte, an Ihre allgemeinen Richtlinien. Wenn dies nullals "Kurzform" für eine leere Liste behandelt werden soll, tun Sie dies auf diese Weise.

Wenn Sie keine konsistente Richtlinie zu nullWerten haben, empfehle ich die folgende:

nullsollte reserviert werden, um Situationen darzustellen, die nicht durch den "normalen" Typ ausgedrückt werden können, z. B. null"Ich weiß nicht". Und das ist eine gute Wahl, da jeder, der versucht, diesen Wert unachtsam zu verwenden, eine Ausnahme bekommt, was das Richtige ist.

Die Verwendung nullals Kurzform für eine leere Liste ist nicht so qualifiziert, da es bereits eine perfekte Darstellung gibt, da es sich um eine Liste mit null Elementen handelt. Und es ist eine technisch schlechte Wahl, da jeder Teil Ihres Codes, der sich mit Listen befasst, gezwungen ist, nach der gültigen Kurzschrift zu suchen null.

Leere Liste

Für eine DeleteItems()Methode bedeutet das Übergeben einer leeren Liste effektiv, nichts zu tun. Ich würde das als Argument zulassen, keine Ausnahme auslösen und einfach schnell zurückkehren.

Natürlich könnte der Anrufer zuerst nach null Elementen suchen und den DeleteItems()Anruf in diesem Fall überspringen . Wenn es sich um eine Web-API handelt, sollte der Anrufer dies aus Effizienzgründen tun, um unnötigen Datenverkehr und Roundtrip-Latenzen zu vermeiden. Aber ich denke nicht, dass Ihre API das erzwingen sollte.

Ralf Kleberhoff
quelle
1

Löst eine Ausnahme aus und behandelt Nullen im aufrufenden Code.

Versuchen Sie als Entwurfsregel, Null als Parameterwerte zu vermeiden. Es wird im Allgemeinen NullPointerExceptions reduzieren, da Nullen wirklich eine Ausnahme sein werden.

Schauen Sie sich außerdem den Rest Ihres Codes an. Wenn dies ein häufiges Muster in Ihrem Projekt ist, bleiben Sie konsistent.

Serprime
quelle
Ich bin gerade dabei, die Struktur meiner Services zu "gestalten", sodass möglicherweise einige Umgestaltungen erforderlich sind, um ungültige Eingaben vorzunehmen, aber nicht viele. Aber ich stimme Ihrem Standpunkt zu, dass Nullen eine Ausnahme werden, sobald ich anfange zu werfen, anstatt sie zu verstecken.
FC
0

Im Allgemeinen sollten Ausnahmen für Ausnahmesituationen reserviert werden, dh wenn der Code im aktuellen Kontext keine angemessene Vorgehensweise bietet.

Sie können diesen Denkprozess auf diese Situation anwenden. Da dies eine öffentliche Klasse mit einer öffentlichen Methode ist, verfügen Sie über eine öffentliche API und haben theoretisch keine Kontrolle darüber, was an sie übergeben wird.

Ihr Code hat keinen Kontext zu dem, was er nennt (wie es nicht sein sollte), und es gibt nichts, was Sie vernünftigerweise mit einem Nullwert tun können. Dies wäre sicherlich ein Kandidat für eine ArgumentNullException.

Richzilla
quelle
msgstr "wenn der Code im aktuellen Kontext keine vernünftige Vorgehensweise hat". Aber ich denke, es hat vernünftige Vorgehensweise, die nichtig zurückkehren soll. Es tut genau das Gleiche wie wenn sie leer Sammlung vorbei, also wenn ich leer Sammlung zulassen , warum dann würde ich nicht zulassen null.
FC
1
@FCin Aufgrund einer leeren Sammlung wissen Sie, dass sie leer ist. Mit nulldir hast du keine Sammlung. Wenn der aufrufende Code eine Auflistung für die Methode liefern soll, stimmt etwas nicht, Sie sollten also werfen. Der einzige Grund, eine Null wie eine leere Auflistung zu behandeln, ist, wenn Sie vernünftigerweise erwarten können, dass der aufrufende Code Null-Auflistungen erzeugt. Wie in anderen Antworten bereits angemerkt, ist etwas meistens nulleine Anomalie. Wenn Sie diese wie leere Auflistungen behandeln, ignorieren Sie möglicherweise ein Problem an einer anderen Stelle im Code.
JAD
@FCin: Auch wenn Sie es nullals leer bezeichnen, ist dies kontextspezifisch für diese Methode. An einer anderen Stelle in derselben Codebasis haben Sie möglicherweise einen IEnumerableoder IContainer-Parameter, der eine Art Filterung ausführt. nullDies bedeutet möglicherweise "kein Filter" (alles zulassen), wohingegen ein leerer Filter bedeutet, dass nichts zulässig ist. Und an einer anderen Stelle nullkönnte explizit "Ich weiß nicht" bedeuten. Da nulldies nicht immer überall dasselbe bedeutet, ist es eine gute Idee, überhaupt keine Bedeutung dafür zu erfinden, es sei denn, diese Bedeutung ist notwendig oder zumindest nützlich für jemanden.
Steve Jessop
0

Bei dieser Frage scheint es sich nicht um Ausnahmen zu handeln, sondern um nullein gültiges Argument.

In erster Linie müssen Sie also entscheiden, ob nulldas Argument dieser Methode ein zulässiger Wert für Sie ist. Wenn ja, brauchen Sie keine Ausnahme. Ist dies nicht der Fall, benötigen Sie eine Ausnahme.

Ob Sie zulassen möchten nulloder nicht, ist umstritten, wie viele Google-Hits zeigen. Das heißt, Sie erhalten keine eindeutige Antwort, und es liegt in gewisser Weise an der Meinung und Tradition des Ortes, an dem Sie arbeiten.

Ein weiterer Streitpunkt ist, ob eine Bibliotheksfunktion in solchen Dingen wirklich streng oder so nachsichtig wie möglich sein sollte, solange sie nicht versucht, fehlerhafte Parameter zu "reparieren". Vergleichen Sie dies mit der Welt der Netzwerkprotokolle, der E-Mail-Übertragung usw. (die Schnittstellenverträge sind, genau wie Methoden in der Programmierung). In der Regel lautet die Richtlinie, dass der Absender das Protokoll so genau wie möglich einhält, während der Empfänger alles daran setzt, mit dem zu arbeiten, was gerade kommt.

Sie müssen sich also entscheiden: Ist es wirklich die Aufgabe einer Bibliotheksmethode, recht umfangreiche Richtlinien wie die nullHandhabung durchzusetzen ? Insbesondere, wenn Ihre Bibliothek auch von anderen Personen verwendet wird (die möglicherweise andere Richtlinien haben).

Ich würde mich wahrscheinlich auf der Seite irren, nullWerte zuzulassen, ihre Semantik zu definieren und zu dokumentieren (dh null = empty arrayin diesem Fall) und keine Ausnahme auszulösen , es sei denn, 99% Ihres anderen ähnlichen Codes ("Bibliotheks" -Stil-Code) machen es anders 'runden.

AnoE
quelle
1
"Ist es wirklich die Aufgabe einer Bibliotheksmethode, ziemlich große Richtlinien wie die Nullbehandlung durchzusetzen?" - nach unten , dass Linie des Denkens liegen behauptet und Debug - Modi, die Ihnen zu erlauben , Hilfe bei der Durchsetzung einer Politik, anstatt es tatsächlich durchzusetzen, wenn es das ist , was Sie tun wollen. Wenn Sie also nulldas Prinzip der Liberalität in dem, was Sie akzeptieren, schlucken wollen , dann wäre das Protokollieren oder sogar das Werfen hilfreich für Leute, deren Absicht es ist, streng in dem zu sein, was sie weitergeben, die aber sowohl ihren Code als auch ihren Code durcheinander gebracht haben ihre Unit-Tests in dem Maße, wie sie nullsowieso bestehen.
Steve Jessop
@SteveJessop, ich weiß nicht genau, ob du gegen den Geist meiner Antwort argumentierst oder ob du in dieser Richtung weitermachst. Das heißt, ich schlage nicht vor, einfach zu schlucken null, sondern es offen im Vertrag der Methode zu erklären, dass es akzeptabel ist (oder nicht, je nachdem, welche Lösung das OP anbietet), und dann die Frage, ob eine Ausnahme geworfen werden soll (oder nicht) löst sich von selbst.
AnoE