De is en as keywords
Dankzij polymorfisme kunnen we dus child en parent-objecten door elkaar gebruiken. De keywords is en as gaan ons helpen om door het bos van objecten het bos nog te zien.
Het is keyword
Het is keyword is een operator die je kan gebruiken om te weten te komen of:
- Een object van een bepaalde datatype is.
- Een object een bepaalde interface bevat (zie volgende hoofdstuk).
De is operator heeft twee operanden nodig en geeft een bool terug als resultaat. Links staat het object dat je test (meestal een variabele), rechts een datatype. Bijvoorbeeld:
bool ditIsEenStudent = mijnStudent is Student;is voorbeeld
Stel dat we volgende drie klassen hebben:
internal class Voertuig {}
internal class Auto: Voertuig{}
internal class Persoon {}Een Auto is een Voertuig. Een Persoon is géén Voertuig.
Stel dat we enkele variabelen hebben als volgt:
Auto mijnAuto = new Auto();
Persoon rambo = new Persoon();We kunnen nu de objecten met is bevragen of ze van een bepaalde type zijn:
if(mijnAuto is Voertuig)
{
Console.WriteLine("mijnAuto is een Voertuig");
}
if(rambo is Voertuig)
{
Console.WriteLine("rambo is een Voertuig");
}De uitvoer zal worden: mijnAuto is een Voertuig.
Met polymorfisme wordt dit voorbeeld echter interessanter. Wat als we een hoop objecten in een lijst van voertuigen plaatsen en nu enkel met de auto’s iets willen doen, dan kan dat:
List<Voertuig> alleMiddelen = new List<Voertuig>();
alleMiddelen.Add(new Voertuig());
alleMiddelen.Add(new Auto());
alleMiddelen.Add(new Voertuig());
foreach (var middel in alleMiddelen)
{
if(middel is Auto)
{
//Doe iets met het huidige voertuig
}
}as keyword met voorbeeld
Wanneer we objecten van het ene naar het andere type willen omzetten dan doen we dit vaak met behulp van casting. Stel dat Student een childklasse is van Mens, en dat je een Mens-variabele hebt waarvan je vermoedt dat er een Student in zit:
Mens fritz = new Student();
Student jos = (Student)fritz;Het probleem bij zo’n downcast is dat dit niet altijd lukt: zat er in fritz een gewone Mens in plaats van een Student, dan kan de omzetting niet. Indien de conversie niet mogelijk is zal een InvalidCastException opgeworpen worden en je programma zal crashen als je niet aan exception handling doet:
Unable to cast object of type ‘ConsoleApp1.Mens’ to type ‘ConsoleApp1.Student’.
(ConsoleApp1 is hier de namespace van het project.) De compiler ziet die fout niet aankomen: hij weet enkel dat er in een Mens-variabele een Student kan zitten. Pas tijdens de uitvoer blijkt of dat ook zo is.
Het as keyword lost dit op. Het keyword zegt aan de compiler “probeer dit object te converteren. Als het niet lukt, zet het dan op null in plaats van een uitzondering op te werpen.”
De code van daarnet herschrijven we dan naar:
Mens fritz = new Student();
Student jos = fritz as Student;Indien nu de casting niet lukt (omdat er in fritz geen Student blijkt te zitten) dan zal jos de waarde null krijgen.
We kunnen dan vervolgens schrijven:
Mens fritz = new Student();
Student jos = fritz as Student;
if(jos != null)
{
//Doe Student-zaken
}as werkt enkel met reference types (objecten van klassen en interfaces). Je kan as dus niet gebruiken op gewone value types zoals int of bool. Iets als int getal = mijnObject as int; zal niet compileren. (Voor value types bestaat een variant met een vraagteken, maar die zien we hier nog niet.)
Wanneer is en wanneer as? Wil je enkel weten of een object van een bepaald type is (een ja/nee-vraag, zonder het daarna te gebruiken), dan volstaat is. Wil je het object daarna meteen gebruiken, dan kan dat met as (één keer omzetten, dan op null controleren). Iets verderop zie je met pattern matching een kortere vorm die het testen en omzetten in één keer doet: die kom je vandaag het vaakst tegen.
Stagiair Steven
Steven heeft een lijst met allerlei objecten en wil, als het eerste object een
Studentis, de naam ervan tonen. De A.I. gaf hem dit:object eersteObject = alleObjecten[0]; object tweedeObject = alleObjecten[1]; if (eersteObject is Student) { Student student = tweedeObject as Student; Console.WriteLine(student.Naam); }“Ik controleer met
isof het eenStudentis, en gebruik daarna netjesasom te casten. Dat zou toch veilig moeten zijn?”, zegt hij.
Deze code compileert en draait soms prima, maar crasht soms met een NullReferenceException. Hoe kan dat, als Steven toch netjes controleert?
Steven controleert inderdaad netjes met is, maar op de verkeerde variabele: hij test eersteObject, maar cast en gebruikt vervolgens tweedeObject. Is eersteObject toevallig een Student, maar tweedeObject niet, dan is de if wel true, maar wordt student via as alsnog null, en crasht student.Naam. De is-check zegt dus niets over tweedeObject: die twee variabelen hebben niets met elkaar te maken. Zoiets ontstaat typisch door onzorgvuldig kopiëren en aanpassen van code: de controle en het gebruik moeten over dezelfde variabele gaan. Steven las zijn eigen code niet nauwkeurig genoeg om dat op te merken.

Pattern matching: is met een variabele
Moderne C# (sinds C# 7) laat toe om de is-controle en het omzetten in één stap te doen. Je plaatst gewoon een variabelenaam achter het type. Slaagt de is-check, dan zit het omgezette object meteen in die variabele klaar voor gebruik. Dit heet pattern matching.
In plaats van:
if(mijnAuto is Voertuig)
{
Voertuig v = (Voertuig)mijnAuto;
//...gebruik v
}schrijf je korter en veiliger:
if(mijnAuto is Voertuig v)
{
//v is hier meteen beschikbaar als Voertuig
}Je zal deze vorm overal in moderne C#-code (en op StackOverflow) tegenkomen, dus het loont om ze te herkennen en te gebruiken.
In dezelfde geest schrijf je je null-controles tegenwoordig vaak met is null en is not null in plaats van == null en != null:
if (jos is not null)
{
//...
}Beide werken; is null / is not null is de modernere, iets veiligere schrijfwijze.
Volgorde van bewerkingen met is en as
De is en as keywords worden gebruikt in logische expressies. Ze hebben dan ook een bepaalde volgorde wanneer ze verwerkt zullen worden. Onze bestaande volgorde van bewerkingen krijgt dus 2 nieuwe leden op lijn 4:
- Logische NIET:
! - Delen en vermenigvuldigen:
*,/,% - Optellen en aftrekken:
+,- - Relationele operators:
<,<=,>,>=énis,as - Gelijkheid:
==,!= - Logische EN:
&& - Logische OF:
||
Steven heeft een lijst met allerlei objecten en wil, als het eerste object een