Een belangrijke bouwsteen van een programma is de functie. Een functie bevat een stuk code dat opgeroepen kan worden in het programma. Werken met functies heeft een aantal voordelen:
Tijdens de oefeningen maakte je reeds gebruik van functieparameters en vulde je het instructieblok van de functie aan. Ook gebruikte je reeds return om een functieresultaat af te leveren. Je zal deze zaken dus zeker herkennen in wat volgt.
Opmerking: In C# spreekt men officieel over ‘methoden’ (methods) i.p.v. over functies. In deze cursus worden de termen ‘functie’ en ‘method’ door elkaar gebruikt, maar duiden ze op hetzelfde.
Bij het ontwerpen van functies kan het snel fout gaan. Om een zo flexibel mogelijk inzetbare functie te maken, beperk je de functie tot één functionaliteit. Bijvoorbeeld: maak geen functie die de oppervlakte van een cirkel berekent en deze op het scherm toont, maar maak een functie die de oppervlakte van de cirkel berekent en deze als functiewaarde aflevert. Op deze manier kan je de oppervlakte niet enkel tonen, maar ook nog voor andere doeleinden gebruiken.
Als voorbeeldfunctie gebruiken we de functie CalcNumbers die:
public static int CalcNumbers(int number1, int number2)
{
int result = 0;
if (number1 >= number2)
{
result = number1 + number2;
}
else
{
result = number1 - number2;
}
return result;
}
Welke onderdelen vinden we in dit voorbeeld terug:
Main of in een andere functie. Voorlopig zijn alle functies die we maken public. Als we later in de cursus met classes gaan werken, wordt dit verder uitgediept.Je kan een functie laten uitvoeren door een functieaanroep. Deze functieaanroep kan in Main of in een andere functie gebeuren.
Enkele manieren om de functie CalcNumbers aan te roepen vind je in de voorbeelden hieronder:
static void Main(string[] args)
{
int calculatedResult = 0;
// Aanroepen van de functie met de argumenten 5 en 7.
// Deze volgorde wordt gebruikt bij het initialiseren van de
// functieparameters.
// Deze functieaanroep heeft volgende initialisaties tot gevolg:
// number1 = 5
// number2 = 7
// Merk op dat het functieresultaat (de returnwaarde) van de functie
// opgevangen wordt in de variabele calculatedResult.
calculatedResult = CalcNumbers(5, 7);
// Aanroepen van de functie met de argumenten 20 en 3.
// Deze functieaanroep heeft volgende initialisaties tot gevolg:
// number1 = 20
// number2 = 3
calculatedResult = CalcNumbers(20, 3);
// Soms vind je onderstaande, alternatieve notatie voor de
// functieaanroep terug. Bij deze syntax speelt de volgorde
// van de functieargumenten tussen haakjes geen rol omdat
// de naam van de functieparameter mee vermeld wordt. Deze
// manier van functieaanroep, met expliciete vermelding van
// de naam van de functieparameters valt onder
// de naam 'named parameters'.
calculatedResult = CalcNumbers(number2: 10, number1: 8);
// Er kunnen ook variabelen als functieargumenten gebruikt worden.
// Natuurlijk moeten deze variabelen reeds op voorhand geïnitialiseerd
// zijn. Een functieaanroep, met gebruik van variabelen
// als functieargumenten, vind je hieronder.
int value1 = 10; // Deze initialisaties gebeuren
int value2 = 4; // eldens in het programma.
calculatedResult = CalcNumbers(value1, value2);
Console.ReadKey();
}
In het bovenstaande voorbeeld, zag je dat het returntype van de functie gelijk is aan het datatype van de waarde die via return als resultaat van de functie gegeven wordt. Soms zal er echter geen resultaat teruggegeven worden via return, maar zal het resultaat bijvoorbeeld op het scherm getoond worden zoals je in onderstaand voorbeeld kan zien.
public static void ShowFullName(string firstname, string lastname)
{
Console.WriteLine($"{firstname} {lastname}");
}
De naam wordt door de functie op het scherm getoond, er is dus geen return-instructie nodig. Een functie zonder een return heeft als returntype `void`.
<div class="header2" markdown = "1">## Optionele (of default) functieparameters
</div>
Het is mogelijk om voor één, meerdere of alle functieparameters een default waarde mee te geven. Indien bij de functieaanroep geen waarde voor deze functieparameters meegegeven wordt, dan wordt de default waarde gebruikt.
Aangezien het niet meer noodzakelijk is om een functieparameter, waarvoor een default waarde voorzien is, een waarde te geven bij de functieaanroep spreken we hier van een optioneel argument.
Voorbeeld: Veronderstel dat de functie `CalcNumbers` vaak opgeroepen wordt met de waarde 10 voor de functieparameter number2. Dan kan de waarde 10 reeds als default waarde bij de functieparameter number2 vermeld worden bij de functie. De functie `CalcNumbers` ziet er dan als volgt uit:
```csharp
public static int CalcNumbers(int number1, int number2 = 10) // default waarde voor number2
{
int result = 0;
if (number1 >= number2)
{
result = number1 + number2;
}
else
{
result = number1 - number2;
}
return result;
}
De functie CalcNumbers kan nu op volgende manieren aangeroepen worden:
static void Main(string[] args)
{
int calculatedResult = 0;
// Met gebruik van de default waarde voor functieargument number2.
// Deze functieaanroep heeft volgende initialisaties tot gevolg:
// number1 = 20
// number2 = 10
calculatedResult = CalcNumbers(20);
// Zonder gebruik van de default waarde voor functieargument number2.
// Indien er een waarde voor een optioneel argument meegegeven wordt bij
// de functieaanroep dan heeft dit voorrang op de default waarde.
// Deze functieaanroep heeft volgende initialisaties tot gevolg:
// number1 = 20
// number2 = 7
calculatedResult = CalcNumbers(20, 7);
Console.ReadKey();
}
Let er steeds op dat je bij het schrijven van een functie de optionele functieparameters als laatste vermeldt in de lijst met functieparameters. Het is immers niet toegelaten posities van functieparameters over te slaan bij de functieaanroep. Bijgevolg moeten de optionele functieparameters als laatste vermeld worden.
Open het project oefening functies 1 en maak oefenreeks 1
Een functie wordt gedefinieerd door zijn naam en zijn lijst van functieparameters. Elke functie moet uniek gedefinieerd zijn, zodat er geen dubbelzinnigheid ontstaat en de compiler weet welke functie er voor een functieaanroep gebruikt moet worden. Toch zal je soms meerdere keren dezelfde naam voor een functie willen gebruiken. Dit kan, zolang je op een andere manier een duidelijk onderscheid maakt tussen functies met dezelfde naam. Het is immers noodzakelijk dat de compiler weet welke functie er wanneer gebruikt moet worden en dit kan nu niet meer bepaald worden a.h.v. de functienaam. Bij functies met dezelfde naam kan je dit onderscheid als volgt inbouwen:
Op bovenstaande manier unieke functies met dezelfde naam creëren is function overloading.
Als eenvoudig voorbeeld maken we een functie die nagaat of een aantal getallen gelijk zijn. Deze getallen worden als functieparameters aan de functie doorgegeven. De functie geeft true indien de getallen gelijk zijn, false indien de getallen niet gelijk zijn. Soms zullen er drie getallen vergeleken moeten worden, soms vier. De getallen zijn steeds van het type integer.
class Program
{
// Versie 1: functie met 3 functieparameters
public static bool CompareNumbers(int n1, int n2, int n3)
{
bool equal = false;
if (n1 == n2 && n2 == n3 && n1 == n3)
{
equal = true;
}
return equal;
}
// Versie 2: functie met 4 functieparameters
public static bool CompareNumbers(int n1, int n2, int n3, int n4)
{
bool equal = false;
if (n1 == n2 && n2 == n3 && n3 == n4)
{
equal = true;
}
return equal;
}
static void Main(string[] args)
{
// Functieaanroep met 3 argumenten
// -> functie 1 wordt aangeroepen.
if (CompareNumbers(5, 3, 7))
{
// bijbehorend instructieblok
}
// Functieaanroep met 3 argumenten
// -> functie 2 wordt aangeroepen.
if (CompareNumbers(1, 5, 2, 9))
{
// bijbehorend instructieblok
}
Console.ReadKey();
}
}
Als eenvoudig voorbeeld maken we een functie Maximum die van een aantal gehele getallen het grootste of van een aantal woorden het laatste in het alfabet als resultaat geeft.
Opmerking: Bij versie twee van de functie Maximum gebruiken we een method uit de class string, namelijk Compare. Deze method returnt volgende waarden afhankelijk van de onderlinge positie van de strings:
class Program
{
// Versie 1: functie met 3 integers als argumenten
public static int Maximum(int v1, int v2, int v3)
{
int max = v1;
if (v2 > max)
{
max = v2;
}
if (v3 > max)
{
max = v3;
}
return max;
}
// Versie 2: functie met 3 strings als argumenten
public static string Maximum(string v1, string v2, string v3)
{
string max = v1;
if (string.Compare(max, v2) < 0)
{
max = v2;
}
if (string.Compare(max, v3) < 0)
{
max = v3;
}
return max;
}
static void Main(string[] args)
{
// Functieaanroep met 3 gehele getallen als argumenten
// -> functie 1 wordt aangeroepen.
int largestNumber = Maximum(2, 20, 7);
// Functieaanroep met 3 strings als argumenten
// -> functie 2 wordt aangeroepen.
string lastWord = Maximum("John", "Steve", "Bill");
Console.WriteLine($"The largest number: {largestNumber}");
Console.WriteLine($"The last name alphabetically: {lastWord}");
Console.ReadKey();
}
}
Open het project oefening functies 1 en maak oefenreeks 2
- {:.} [Voorbeeld: function overloading a.h.v. het aantal functieparameters](#voorbeeld-function-overloading-ahv-het-aantal-functieparameters)
- {:.} [Voorbeeld: function overloading a.h.v. het type functieparameters](#voorbeeld-function-overloading-ahv-het-type-functieparameters)