Waarom staat C# je toe om ‘null’ te gooien?

Tijdens het schrijven van een bijzonder complexe code voor het afhandelen van uitzonderingen, vroeg iemand, moet je er dan niet voor zorgen dat je uitzonderingsobject niet null is? En ik zei natuurlijk niet, maar besloot toen om het te proberen. Blijkbaar kun je null gooien, maar het wordt nog steeds ergens in een uitzondering omgezet.

Waarom is dit toegestaan?

throw null;

In dit fragment is ‘ex’ gelukkig niet nul, maar zou het dat ooit kunnen zijn?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?
  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}

Antwoord 1, autoriteit 100%

Omdat de taalspecificatie daar een expressie van het type System.Exceptionverwacht (daarom is nullgeldig in die context) en deze expressie niet beperkt tot niet-nul. Over het algemeen kan het op geen enkele manier detecteren of de waarde van die uitdrukking nullis of niet. Het zou het stopprobleem moeten oplossen. De runtime zal hoe dan ook te maken krijgen met het nullgeval. Zie:

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 

Ze zouden natuurlijk het specifieke geval van het letterlijk ongeldig maken van de nullongeldig kunnen maken, maar dat zou niet veel helpen, dus waarom zou je specificatieruimte verspillen en de consistentie verminderen voor weinig voordeel?

Disclaimer (voordat ik geslagen word door Eric Lippert): Dit is mijn eigenspeculatie over de redenering achter deze ontwerpbeslissing. Ik ben natuurlijk niet bij de ontwerpvergadering geweest 😉


Het antwoord op uw tweede vraag, of een expressievariabele die binnen een catch-clausule is gevangen, ooit null kan zijn: terwijl de C#-specificatie zwijgt over de vraag of andere talen ervoor kunnen zorgen dat een null-uitzondering wordt gepropageerd, het definieert wel de manier waarop uitzonderingen worden verspreid:

De eventuele catch-clausules worden in volgorde van verschijnen onderzocht om een ​​geschikte handler voor de uitzondering te vinden. De eerste catch-clausule die het uitzonderingstype specificeert of een basistype van het uitzonderingstypewordt als een overeenkomst beschouwd. Een algemene catch-clausule wordt beschouwd als een overeenkomst voor elk type uitzondering. […]

Voor nullis de vetgedrukte verklaring onwaar. Dus, hoewel puur gebaseerd op wat de C#-specificatie zegt, kunnen we niet zeggen dat de onderliggende runtime nooit nul zal genereren, we kunnen er zeker van zijn dat zelfs als dat het geval is, het alleen wordt afgehandeld door de generieke catch {}clausule.

Voor C#-implementaties op de CLI kunnen we verwijzen naar de ECMA 335-specificatie. Dat document definieert alle uitzonderingen die de CLI intern genereert (waarvan geen nullis) en vermeldt dat door de gebruiker gedefinieerde uitzonderingsobjecten worden gegenereerd door de instructie throw. De beschrijving voor die instructie is vrijwel identiek aan de C# throw-instructie (behalve dat het het type object niet beperkt tot System.Exception):

Beschrijving:

De throwinstructie gooit het exception-object (type O) op de stapel en maakt de stapel leeg. Voor details van het uitzonderingsmechanisme, zie Partitie I.
[Opmerking: hoewel de CLI toestaat dat elk object kan worden gegenereerd, beschrijft de CLS een specifieke uitzonderingsklasse die moet worden gebruikt voor taalinteroperabiliteit. eindnoot]

Uitzonderingen:

System.NullReferenceExceptionwordt gegenereerd als objnullis.

Juistheid:

De juiste CIL zorgt ervoor dat het object altijd nullof een objectreferentie is (d.w.z. van het type O).

Ik geloof dat deze voldoende zijn om te concluderen dat gevangen uitzonderingen nooit nullzijn.


Antwoord 2, autoriteit 29%

Blijkbaar kun je null gooien, maar het wordt nog steeds ergens in een uitzondering omgezet.

Een poging om een ​​null-object te gooien resulteert in een (volledig niet-gerelateerde) Null Reference Exception.

Vragen waarom je nullmag gooien is hetzelfde als vragen waarom je dit mag doen:

object o = null;
o.ToString();

Antwoord 3, autoriteit 7%

Hoewel het misschien niet mogelijk is om null in C# te gooien omdat de worp dat zal detecteren en er een NullReferenceException van zal maken, IS het wel mogelijk om null te ontvangen… Ik ontvang dat nu toevallig, waardoor mijn vangst ( die niet verwachtte dat ‘ex’ null zou zijn) om een ​​nulreferentie-uitzondering te ervaren die er vervolgens toe leidt dat mijn app sterft (aangezien dat de laatste vangst was).

Dus, hoewel we null niet kunnen gooien vanuit C#, kan de onderwereld null gooien, dus je buitenste vangst (uitzondering ex) kan maar beter voorbereid zijn om het te ontvangen. Gewoon ter informatie.


Antwoord 4, autoriteit 5%

Genomen van hier:

Als je deze expressie gebruikt in je C#
code zal het een gooien
NullReferentieuitzondering. Dat is
omdat de throw-instructie een . nodig heeft
object van het type Exception als single
parameter. Maar dit object is
null in mijn voorbeeld.


Antwoord 5, autoriteit 3%

Proberen te antwoorden “..gelukkig is ‘ex’ niet null, maar zou het ooit kunnen?”:

Omdat we aantoonbaar geen uitzonderingen kunnen genereren die null zijn, hoeft een catch-clausule ook nooit een uitzondering op te vangen die null is. Ex kan dus nooit nul zijn.

Ik zie nu dat deze vraag in feite al is gesteld.


Antwoord 6, autoriteit 2%

Ik denk dat je dat misschien niet kunt — wanneer je null probeert te gooien, kan het niet, dus het doet wat het zou moeten doen in een foutgeval, namelijk een null-referentie-uitzondering gooien. Je gooit dus niet echt de nul, je gooit de nul niet, wat resulteert in een worp.


Antwoord 7

Houd er rekening mee dat een uitzondering details bevat over waar de uitzondering wordt gegenereerd. Aangezien de constructor geen idee heeft waar hij moet worden gegooid, is het alleen maar logisch dat de worpmethode die details in het object injecteert op het punt waar de worp is. Met andere woorden, de CLR probeert gegevens in null te injecteren, wat een NullReferenceException activeert.

Ik weet niet zeker of dit precies is wat er gebeurt, maar het verklaart het fenomeen.

Ervan uitgaande dat dit waar is (en ik kan geen betere manier bedenken om ex nul te laten zijn dan nul te gooien;), zou dat betekenen dat ex onmogelijk nul kan zijn.

Other episodes