Das ist eine Art allgemeine Frage (aber ich verwende C #). Was ist der beste Weg (Best Practice)? Geben Sie für eine Methode, die eine Sammlung als Rückgabetyp hat, null oder leere Sammlung zurück?
Das ist eine Art allgemeine Frage (aber ich verwende C #). Was ist der beste Weg (Best Practice)? Geben Sie für eine Methode, die eine Sammlung als Rückgabetyp hat, null oder leere Sammlung zurück?
Antworten:
Leere Sammlung. Immer.
Das ist scheiße:
if(myInstance.CollectionProperty != null)
{
foreach(var item in myInstance.CollectionProperty)
/* arrgh */
}
Es wird als bewährte Methode angesehen, NIEMALS zurückzukehren, null
wenn eine Sammlung oder eine Aufzählung zurückgegeben wird. Geben Sie IMMER eine leere Aufzählung / Sammlung zurück. Es verhindert den oben genannten Unsinn und verhindert, dass Ihr Auto von Mitarbeitern und Benutzern Ihrer Klassen angeregt wird.
Wenn Sie über Eigenschaften sprechen, stellen Sie Ihre Eigenschaft immer einmal ein und vergessen Sie sie
public List<Foo> Foos {public get; private set;}
public Bar() { Foos = new List<Foo>(); }
In .NET 4.6.1 können Sie dies ziemlich stark komprimieren:
public List<Foo> Foos { get; } = new List<Foo>();
Wenn Sie über Methoden sprechen, die Enumerables zurückgeben, können Sie einfach eine leere Enumerable anstelle von null
... zurückgeben.
public IEnumerable<Foo> GetMyFoos()
{
return InnerGetFoos() ?? Enumerable.Empty<Foo>();
}
Die Verwendung Enumerable.Empty<T>()
kann als effizienter angesehen werden, als beispielsweise eine neue leere Sammlung oder ein neues Array zurückzugeben.
IEnumerable
oder ICollection
nicht. Wie auch immer, wenn Sie etwas vom Typ auswählen, geben ICollection
sie auch zurück null
... Ich möchte, dass sie eine leere Sammlung zurückgeben, aber ich bin auf sie gestoßen null
, also dachte ich, ich würde es hier nur erwähnen. Ich würde sagen, der Standardwert einer Sammlung von Aufzählungszeichen ist leer und nicht null. Ich wusste nicht, dass es ein so sensibles Thema ist.
Aus den Framework Design Guidelines 2nd Edition (S. 256):
Geben Sie KEINE Nullwerte von Sammlungseigenschaften oder von Methoden zurück, die Sammlungen zurückgeben. Geben Sie stattdessen eine leere Sammlung oder ein leeres Array zurück.
Hier ist ein weiterer interessanter Artikel über die Vorteile der Nichtrückgabe von Nullen (ich habe versucht, etwas in Brad Abrams Blog zu finden, und er hat auf den Artikel verlinkt).
Bearbeiten - wie Eric Lippert jetzt die ursprüngliche Frage kommentiert hat, möchte ich auch auf seinen ausgezeichneten Artikel verlinken .
Hängt von Ihrem Vertrag und Ihrem konkreten Fall ab . Im Allgemeinen ist es am besten, leere Sammlungen zurückzugeben , aber manchmal ( selten) ):
null
könnte etwas Spezifischeres bedeuten;null
.Einige konkrete Beispiele:
null
würde bedeuten, dass das Element fehlt, während eine leere Sammlung ein redundantes (und möglicherweise falsches) Element rendern würde.<collection />
Es gibt noch einen weiteren Punkt, der noch nicht erwähnt wurde. Betrachten Sie den folgenden Code:
public static IEnumerable<string> GetFavoriteEmoSongs()
{
yield break;
}
Die C # -Sprache gibt beim Aufrufen dieser Methode einen leeren Enumerator zurück. Um mit dem Sprachdesign (und damit den Erwartungen des Programmierers) übereinzustimmen, sollte daher eine leere Sammlung zurückgegeben werden.
Leer ist viel verbraucherfreundlicher.
Es gibt eine klare Methode, um eine leere Aufzählung zu erstellen:
Enumerable.Empty<Element>()
Es scheint mir, dass Sie den Wert zurückgeben sollten, der im Kontext semantisch korrekt ist, was auch immer das sein mag. Eine Regel mit der Aufschrift "Immer eine leere Sammlung zurückgeben" erscheint mir etwas simpel.
Angenommen, wir haben beispielsweise in einem System für ein Krankenhaus eine Funktion, die eine Liste aller früheren Krankenhausaufenthalte der letzten 5 Jahre zurückgeben soll. Wenn der Kunde nicht im Krankenhaus war, ist es sinnvoll, eine leere Liste zurückzugeben. Was aber, wenn der Kunde diesen Teil des Zulassungsformulars leer gelassen hat? Wir brauchen einen anderen Wert, um "leere Liste" von "keine Antwort" oder "weiß nicht" zu unterscheiden. Wir könnten eine Ausnahme auslösen, aber dies ist nicht unbedingt eine Fehlerbedingung und führt uns nicht unbedingt aus dem normalen Programmablauf heraus.
Ich war oft frustriert von Systemen, die nicht zwischen Null und Keine Antwort unterscheiden können. Ich wurde mehrmals von einem System aufgefordert, eine Zahl einzugeben. Ich gebe Null ein und erhalte die Fehlermeldung, dass ich einen Wert in dieses Feld eingeben muss. Ich habe es gerade getan: Ich habe Null eingegeben! Aber es akzeptiert keine Null, weil es es nicht von keiner Antwort unterscheiden kann.
Antwort an Saunders:
Ja, ich gehe davon aus, dass es einen Unterschied zwischen "Person hat die Frage nicht beantwortet" und "Die Antwort war Null" gibt. Das war der Punkt des letzten Absatzes meiner Antwort. Viele Programme sind nicht in der Lage, "Weiß nicht" von Leer oder Null zu unterscheiden, was mir als potenziell schwerwiegender Fehler erscheint. Zum Beispiel habe ich vor ungefähr einem Jahr ein Haus gekauft. Ich ging zu einer Immobilien-Website und es gab viele Häuser mit einem Preis von 0 US-Dollar. Hört sich für mich ziemlich gut an: Sie verschenken diese Häuser kostenlos! Aber ich bin sicher, die traurige Realität war, dass sie den Preis einfach nicht eingegeben hatten. In diesem Fall können Sie sagen: "Nun, offensichtlich Null bedeutet, dass sie den Preis nicht eingegeben haben - niemand wird ein Haus kostenlos verschenken." Die Website listete aber auch die durchschnittlichen Angebots- und Verkaufspreise von Häusern in verschiedenen Städten auf. Ich kann nicht anders, als mich zu fragen, ob der Durchschnitt die Nullen nicht enthielt, was für einige Orte einen falsch niedrigen Durchschnitt ergibt. dh was ist der Durchschnitt von 100.000 $; 120.000 US-Dollar; und "weiß nicht"? Technisch lautet die Antwort "Weiß nicht". Was wir wahrscheinlich wirklich sehen wollen, sind 110.000 US-Dollar. Aber was wir wahrscheinlich bekommen werden, sind 73.333 Dollar, was völlig falsch wäre. Was wäre, wenn wir dieses Problem auf einer Website hätten, auf der Benutzer online bestellen können? (Unwahrscheinlich für Immobilien, aber ich bin sicher, dass Sie dies bei vielen anderen Produkten gesehen haben.) Würden wir wirklich wollen, dass "Preis noch nicht angegeben" als "kostenlos" interpretiert wird? Dies ergibt für einige Orte einen falsch niedrigen Durchschnitt. dh was ist der Durchschnitt von 100.000 $; 120.000 US-Dollar; und "weiß nicht"? Technisch lautet die Antwort "Weiß nicht". Was wir wahrscheinlich wirklich sehen wollen, sind 110.000 US-Dollar. Aber was wir wahrscheinlich bekommen werden, sind 73.333 Dollar, was völlig falsch wäre. Was wäre, wenn wir dieses Problem auf einer Website hätten, auf der Benutzer online bestellen können? (Unwahrscheinlich für Immobilien, aber ich bin sicher, dass Sie dies bei vielen anderen Produkten gesehen haben.) Würden wir wirklich wollen, dass "Preis noch nicht angegeben" als "kostenlos" interpretiert wird? Dies ergibt für einige Orte einen falsch niedrigen Durchschnitt. dh was ist der Durchschnitt von 100.000 $; 120.000 US-Dollar; und "weiß nicht"? Technisch lautet die Antwort "Weiß nicht". Was wir wahrscheinlich wirklich sehen wollen, sind 110.000 US-Dollar. Aber was wir wahrscheinlich bekommen werden, sind 73.333 Dollar, was völlig falsch wäre. Was wäre, wenn wir dieses Problem auf einer Website hätten, auf der Benutzer online bestellen können? (Unwahrscheinlich für Immobilien, aber ich bin sicher, dass Sie dies bei vielen anderen Produkten gesehen haben.) Würden wir wirklich wollen, dass "Preis noch nicht angegeben" als "kostenlos" interpretiert wird? das wäre völlig falsch. Was wäre, wenn wir dieses Problem auf einer Website hätten, auf der Benutzer online bestellen können? (Unwahrscheinlich für Immobilien, aber ich bin sicher, dass Sie dies bei vielen anderen Produkten gesehen haben.) Würden wir wirklich wollen, dass "Preis noch nicht angegeben" als "kostenlos" interpretiert wird? das wäre völlig falsch. Was wäre, wenn wir dieses Problem auf einer Website hätten, auf der Benutzer online bestellen können? (Unwahrscheinlich für Immobilien, aber ich bin sicher, dass Sie dies bei vielen anderen Produkten gesehen haben.) Würden wir wirklich wollen, dass "Preis noch nicht angegeben" als "kostenlos" interpretiert wird?
RE hat zwei separate Funktionen, ein "Gibt es welche?" und ein "wenn ja, was ist es?" Ja, das könnten Sie sicherlich tun, aber warum sollten Sie das wollen? Jetzt muss das aufrufende Programm zwei Aufrufe anstelle von einem tätigen. Was passiert, wenn ein Programmierer das "any" nicht aufruft? und geht direkt zum "Was ist das?" ? Gibt das Programm eine falsch führende Null zurück? Eine Ausnahme werfen? Einen undefinierten Wert zurückgeben? Es schafft mehr Code, mehr Arbeit und mehr potenzielle Fehler.
Der einzige Vorteil, den ich sehe, ist, dass Sie eine beliebige Regel einhalten können. Gibt es einen Vorteil dieser Regel, der es sich lohnt, sie einzuhalten? Wenn nicht, warum dann?
Antwort auf Jammycakes:
Überlegen Sie, wie der eigentliche Code aussehen würde. Ich weiß, dass die Frage C # lautete, aber entschuldigen Sie, wenn ich Java schreibe. Mein C # ist nicht sehr scharf und das Prinzip ist das gleiche.
Mit einer Null-Rückgabe:
HospList list=patient.getHospitalizationList(patientId);
if (list==null)
{
// ... handle missing list ...
}
else
{
for (HospEntry entry : list)
// ... do whatever ...
}
Mit einer separaten Funktion:
if (patient.hasHospitalizationList(patientId))
{
// ... handle missing list ...
}
else
{
HospList=patient.getHospitalizationList(patientId))
for (HospEntry entry : list)
// ... do whatever ...
}
Es ist tatsächlich ein oder zwei Zeilen weniger Code mit der Null-Rückgabe, sodass der Anrufer nicht mehr belastet wird, sondern weniger.
Ich sehe nicht, wie es ein trockenes Problem schafft. Es ist nicht so, dass wir den Anruf zweimal ausführen müssen. Wenn wir immer das Gleiche tun wollten, wenn die Liste nicht vorhanden ist, könnten wir die Behandlung möglicherweise auf die Funktion "Get-List" beschränken, anstatt den Anrufer dies tun zu lassen. Daher wäre das Einfügen des Codes in den Anrufer eine DRY-Verletzung. Aber wir wollen mit ziemlicher Sicherheit nicht immer das Gleiche tun. In Funktionen, in denen die Liste verarbeitet werden muss, ist eine fehlende Liste ein Fehler, der die Verarbeitung möglicherweise anhält. Aber auf einem Bearbeitungsbildschirm möchten wir die Verarbeitung sicherlich nicht anhalten, wenn sie noch keine Daten eingegeben haben. Wir möchten, dass sie Daten eingeben. Die Behandlung von "keine Liste" muss also auf die Anrufer-Ebene auf die eine oder andere Weise erfolgen. Und ob wir das mit einer Null-Rückgabe oder einer separaten Funktion machen, spielt für das größere Prinzip keine Rolle.
Sicher, wenn der Aufrufer nicht nach null sucht, kann das Programm mit einer Nullzeigerausnahme fehlschlagen. Aber wenn es eine separate "got any" -Funktion gibt und der Aufrufer diese Funktion nicht aufruft, sondern blind die "get list" -Funktion aufruft, was passiert dann? Wenn es eine Ausnahme auslöst oder auf andere Weise fehlschlägt, ist das so ziemlich das Gleiche wie das, was passieren würde, wenn es null zurückgibt und nicht danach sucht. Wenn eine leere Liste zurückgegeben wird, ist das einfach falsch. Sie können nicht zwischen "Ich habe eine Liste mit null Elementen" und "Ich habe keine Liste" unterscheiden. Es ist, als würde man für den Preis Null zurückgeben, wenn der Benutzer keinen Preis eingegeben hat: Es ist einfach falsch.
Ich sehe nicht, wie das Anhängen eines zusätzlichen Attributs an die Sammlung hilft. Der Anrufer muss es noch überprüfen. Wie ist das besser als nach Null zu suchen? Das absolut Schlimmste, was passieren kann, ist, dass der Programmierer vergisst, es zu überprüfen, und falsche Ergebnisse liefert.
Eine Funktion, die null zurückgibt, ist keine Überraschung, wenn der Programmierer mit dem Konzept von null vertraut ist, das "keinen Wert haben" bedeutet. Ich denke, jeder kompetente Programmierer hätte davon hören sollen, ob er es für eine gute Idee hält oder nicht. Ich denke, eine separate Funktion zu haben, ist eher ein "Überraschungs" -Problem. Wenn ein Programmierer mit der API nicht vertraut ist und einen Test ohne Daten ausführt, stellt er schnell fest, dass er manchmal eine Null zurückerhält. Aber wie würde er die Existenz einer anderen Funktion entdecken, wenn ihm nicht in den Sinn käme, dass es eine solche Funktion geben könnte, und er die Dokumentation überprüft und die Dokumentation vollständig und verständlich ist? Ich hätte viel lieber eine Funktion, die mir immer eine aussagekräftige Antwort gibt, als zwei Funktionen, die ich kennen und daran denken muss, beide aufzurufen.
Wenn eine leere Sammlung semantisch Sinn macht, kehre ich lieber zurück. Rückgabe einer leeren Sammlung für GetMessagesInMyInbox()
Mitteilungen "Sie haben wirklich keine Nachrichten in Ihrem Posteingang", während die Rückgabe null
hilfreich sein kann, um mitzuteilen, dass nicht genügend Daten verfügbar sind, um zu sagen, wie die möglicherweise zurückgegebene Liste aussehen soll.
null
Wert sicherlich nicht vernünftig. Ich habe allgemeiner darüber nachgedacht. Ausnahmen sind auch großartig, um die Tatsache zu kommunizieren, dass etwas schief gelaufen ist, aber wenn die "unzureichenden Daten", auf die Bezug genommen wird, perfekt erwartet werden, dann würde das Auslösen einer Ausnahme ein schlechtes Design bedeuten. Ich denke eher an ein Szenario, in dem es durchaus möglich und überhaupt kein Fehler ist, dass die Methode manchmal nicht in der Lage ist, eine Antwort zu berechnen.
Die Rückgabe von null könnte effizienter sein, da kein neues Objekt erstellt wird. Es würde jedoch häufig auch eine null
Überprüfung (oder Ausnahmebehandlung) erfordern .
Semantisch gesehen null
und eine leere Liste bedeuten nicht dasselbe. Die Unterschiede sind subtil und eine Wahl kann in bestimmten Fällen besser sein als die andere.
Dokumentieren Sie es unabhängig von Ihrer Wahl, um Verwirrung zu vermeiden.
Man könnte argumentieren, dass die Argumentation hinter Null Object Pattern ähnlich ist wie die für die Rückgabe der leeren Sammlung.
Es kommt auf die Situation an. Wenn es sich um einen Sonderfall handelt, geben Sie null zurück. Wenn die Funktion zufällig eine leere Sammlung zurückgibt, ist dies offensichtlich in Ordnung. Die Rückgabe einer leeren Sammlung als Sonderfall aufgrund ungültiger Parameter oder aus anderen Gründen ist jedoch KEINE gute Idee, da dadurch eine Sonderfallbedingung maskiert wird.
Eigentlich ziehe ich es in diesem Fall normalerweise vor, eine Ausnahme auszulösen, um sicherzustellen, dass sie WIRKLICH nicht ignoriert wird :)
Zu sagen, dass der Code dadurch robuster wird (indem eine leere Sammlung zurückgegeben wird), da sie die Nullbedingung nicht behandeln müssen, ist schlecht, da lediglich ein Problem maskiert wird, das vom aufrufenden Code behandelt werden sollte.
Ich würde argumentieren, dass dies null
nicht dasselbe ist wie eine leere Sammlung, und Sie sollten auswählen, welche am besten für Ihre Rückgabe steht. In den meisten Fällennull
ist nichts (außer in SQL). Eine leere Sammlung ist etwas, wenn auch ein leeres Etwas.
Wenn Sie sich für die eine oder andere entscheiden müssen, würde ich sagen, dass Sie eher zu einer leeren Sammlung als zu Null tendieren sollten. Es gibt jedoch Situationen, in denen eine leere Sammlung nicht mit einem Nullwert identisch ist.
Denken Sie immer zugunsten Ihrer Kunden (die Ihre API verwenden):
Die Rückgabe von 'null' führt sehr häufig zu Problemen mit Clients, die Nullprüfungen nicht korrekt verarbeiten, was zur Laufzeit zu einer NullPointerException führt. Ich habe Fälle gesehen, in denen eine solche fehlende Nullprüfung ein vorrangiges Produktionsproblem erzwang (ein Client, der für jeden (...) einen Nullwert verwendet hat). Während des Tests trat das Problem nicht auf, da die bearbeiteten Daten geringfügig voneinander abweichen.
Ich möchte hier mit einem geeigneten Beispiel erklären.
Betrachten Sie hier einen Fall.
int totalValue = MySession.ListCustomerAccounts()
.FindAll(ac => ac.AccountHead.AccountHeadID
== accountHead.AccountHeadID)
.Sum(account => account.AccountValue);
Hier Betrachten Sie die Funktionen, die ich benutze ..
1. ListCustomerAccounts() // User Defined
2. FindAll() // Pre-defined Library Function
Ich kann leicht verwenden ListCustomerAccount
und FindAll
statt.,.
int totalValue = 0;
List<CustomerAccounts> custAccounts = ListCustomerAccounts();
if(custAccounts !=null ){
List<CustomerAccounts> custAccountsFiltered =
custAccounts.FindAll(ac => ac.AccountHead.AccountHeadID
== accountHead.AccountHeadID );
if(custAccountsFiltered != null)
totalValue = custAccountsFiltered.Sum(account =>
account.AccountValue).ToString();
}
HINWEIS: Da AccountValue nicht aktiviert ist null
, wird die Funktion Sum () nicht zurückgegeben null
. Daher kann ich sie direkt verwenden.
Leere Sammlung. Wenn Sie C # verwenden, wird davon ausgegangen, dass die Maximierung der Systemressourcen nicht unbedingt erforderlich ist. Die Rückgabe der leeren Sammlung ist zwar weniger effizient, für die beteiligten Programmierer jedoch viel bequemer (aus dem oben beschriebenen Grund).
In den meisten Fällen ist es besser, eine leere Sammlung zurückzugeben.
Der Grund dafür ist die bequeme Implementierung des Anrufers, der konsistente Vertrag und die einfachere Implementierung.
Wenn eine Methode null zurückgibt, um ein leeres Ergebnis anzuzeigen, muss der Aufrufer zusätzlich zur Aufzählung einen Nullprüfadapter implementieren. Dieser Code wird dann in verschiedenen Aufrufern dupliziert. Warum also nicht diesen Adapter in die Methode einfügen, damit er wiederverwendet werden kann?
Eine gültige Verwendung von null für IEnumerable kann ein Hinweis auf ein fehlendes Ergebnis oder einen Operationsfehler sein. In diesem Fall sollten jedoch andere Techniken in Betracht gezogen werden, z. B. das Auslösen einer Ausnahme.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace StackOverflow.EmptyCollectionUsageTests.Tests
{
/// <summary>
/// Demonstrates different approaches for empty collection results.
/// </summary>
class Container
{
/// <summary>
/// Elements list.
/// Not initialized to an empty collection here for the purpose of demonstration of usage along with <see cref="Populate"/> method.
/// </summary>
private List<Element> elements;
/// <summary>
/// Gets elements if any
/// </summary>
/// <returns>Returns elements or empty collection.</returns>
public IEnumerable<Element> GetElements()
{
return elements ?? Enumerable.Empty<Element>();
}
/// <summary>
/// Initializes the container with some results, if any.
/// </summary>
public void Populate()
{
elements = new List<Element>();
}
/// <summary>
/// Gets elements. Throws <see cref="InvalidOperationException"/> if not populated.
/// </summary>
/// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>.</returns>
public IEnumerable<Element> GetElementsStrict()
{
if (elements == null)
{
throw new InvalidOperationException("You must call Populate before calling this method.");
}
return elements;
}
/// <summary>
/// Gets elements, empty collection or nothing.
/// </summary>
/// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>, with zero or more elements, or null in some cases.</returns>
public IEnumerable<Element> GetElementsInconvenientCareless()
{
return elements;
}
/// <summary>
/// Gets elements or nothing.
/// </summary>
/// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>, with elements, or null in case of empty collection.</returns>
/// <remarks>We are lucky that elements is a List, otherwise enumeration would be needed.</remarks>
public IEnumerable<Element> GetElementsInconvenientCarefull()
{
if (elements == null || elements.Count == 0)
{
return null;
}
return elements;
}
}
class Element
{
}
/// <summary>
/// http://stackoverflow.com/questions/1969993/is-it-better-to-return-null-or-empty-collection/
/// </summary>
class EmptyCollectionTests
{
private Container container;
[SetUp]
public void SetUp()
{
container = new Container();
}
/// <summary>
/// Forgiving contract - caller does not have to implement null check in addition to enumeration.
/// </summary>
[Test]
public void UseGetElements()
{
Assert.AreEqual(0, container.GetElements().Count());
}
/// <summary>
/// Forget to <see cref="Container.Populate"/> and use strict method.
/// </summary>
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void WrongUseOfStrictContract()
{
container.GetElementsStrict().Count();
}
/// <summary>
/// Call <see cref="Container.Populate"/> and use strict method.
/// </summary>
[Test]
public void CorrectUsaOfStrictContract()
{
container.Populate();
Assert.AreEqual(0, container.GetElementsStrict().Count());
}
/// <summary>
/// Inconvenient contract - needs a local variable.
/// </summary>
[Test]
public void CarefulUseOfCarelessMethod()
{
var elements = container.GetElementsInconvenientCareless();
Assert.AreEqual(0, elements == null ? 0 : elements.Count());
}
/// <summary>
/// Inconvenient contract - duplicate call in order to use in context of an single expression.
/// </summary>
[Test]
public void LameCarefulUseOfCarelessMethod()
{
Assert.AreEqual(0, container.GetElementsInconvenientCareless() == null ? 0 : container.GetElementsInconvenientCareless().Count());
}
[Test]
public void LuckyCarelessUseOfCarelessMethod()
{
// INIT
var praySomeoneCalledPopulateBefore = (Action)(()=>container.Populate());
praySomeoneCalledPopulateBefore();
// ACT //ASSERT
Assert.AreEqual(0, container.GetElementsInconvenientCareless().Count());
}
/// <summary>
/// Excercise <see cref="ArgumentNullException"/> because of null passed to <see cref="Enumerable.Count{TSource}(System.Collections.Generic.IEnumerable{TSource})"/>
/// </summary>
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void UnfortunateCarelessUseOfCarelessMethod()
{
Assert.AreEqual(0, container.GetElementsInconvenientCareless().Count());
}
/// <summary>
/// Demonstrates the client code flow relying on returning null for empty collection.
/// Exception is due to <see cref="Enumerable.First{TSource}(System.Collections.Generic.IEnumerable{TSource})"/> on an empty collection.
/// </summary>
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void UnfortunateEducatedUseOfCarelessMethod()
{
container.Populate();
var elements = container.GetElementsInconvenientCareless();
if (elements == null)
{
Assert.Inconclusive();
}
Assert.IsNotNull(elements.First());
}
/// <summary>
/// Demonstrates the client code is bloated a bit, to compensate for implementation 'cleverness'.
/// We can throw away the nullness result, because we don't know if the operation succeeded or not anyway.
/// We are unfortunate to create a new instance of an empty collection.
/// We might have already had one inside the implementation,
/// but it have been discarded then in an effort to return null for empty collection.
/// </summary>
[Test]
public void EducatedUseOfCarefullMethod()
{
Assert.AreEqual(0, (container.GetElementsInconvenientCarefull() ?? Enumerable.Empty<Element>()).Count());
}
}
}
Ich nenne es meinen Milliarden-Dollar-Fehler… Zu dieser Zeit entwarf ich das erste umfassende Typensystem für Referenzen in einer objektorientierten Sprache. Mein Ziel war es sicherzustellen, dass jede Verwendung von Referenzen absolut sicher ist, wobei die Überprüfung automatisch vom Compiler durchgeführt wird. Aber ich konnte der Versuchung nicht widerstehen, eine Nullreferenz einzugeben, einfach weil es so einfach zu implementieren war. Dies hat zu unzähligen Fehlern, Schwachstellen und Systemabstürzen geführt, die in den letzten vierzig Jahren wahrscheinlich eine Milliarde Dollar an Schmerzen und Schäden verursacht haben. - Tony Hoare, Erfinder von ALGOL W.
Sehen Sie hier für eine aufwendige Scheiße Sturm über null
im Allgemeinen. Ich stimme der Aussage nicht zu, die undefined
eine andere ist null
, aber es lohnt sich immer noch zu lesen. Und es erklärt, warum Sie überhaupt vermeiden sollten null
und nicht nur für den Fall, dass Sie gefragt haben. Das Wesentliche ist, dass null
in jeder Sprache ein Sonderfall vorliegt. Sie müssen null
als Ausnahme denken . undefined
unterscheidet sich in dieser Hinsicht, dass Code, der sich mit undefiniertem Verhalten befasst, in den meisten Fällen nur ein Fehler ist. C und die meisten anderen Sprachen haben ebenfalls ein undefiniertes Verhalten, aber die meisten von ihnen haben keine Kennung dafür in der Sprache.
Unter dem Gesichtspunkt des Komplexitätsmanagements, einem primären Ziel des Software-Engineerings, möchten wir eine unnötige Verbreitung vermeiden zyklomatische Komplexität auf die Clients einer API übertragen wird. Das Zurückgeben einer Null an den Client entspricht dem Zurückgeben der zyklomatischen Komplexitätskosten eines anderen Codezweigs.
(Dies entspricht einer Unit-Test-Belastung. Sie müssten zusätzlich zum leeren Collection-Return-Fall einen Test für den Null-Return-Fall schreiben.)