Les 2
C# in een notendop voor Python-kenners
De belangrijkste C#-syntax naast Python: typen, klassen en collecties.
🎯 Na deze les kun je
- Python-code lezen en vertalen naar C#
- de .NET CLI gebruiken
- List en Dictionary gebruiken
Je kunt programmeren in Python. Goed nieuws: bijna alles wat je weet, werkt in C# ook. Variabelen, if, lussen, functies, lijsten en dictionaries bestaan allemaal, alleen ziet de schrijfwijze er anders uit. Het grootste verschil is dat C# statisch getypeerd is: elke variabele heeft een vast type, en de compiler controleert dat voordat je programma draait. In deze les vertaal je Python-code naar C#, en leer je de dotnet-opdrachtregel kennen.
.NET installeren en de CLI
C# draait op .NET, een gratis platform van Microsoft voor Windows, macOS en Linux. Installeer de .NET 10 SDK (de huidige LTS-versie, long-term support) via dot.net. Controleer daarna:
dotnet --version
Je krijgt iets als 10.0.100. Alles wat je met .NET doet, loopt via het commando dotnet:
| Commando | Doet |
|---|---|
dotnet new console -n Kassa |
nieuw console-project in de map Kassa |
dotnet run |
bouwen en uitvoeren |
dotnet build |
alleen bouwen (fouten zoeken) |
dotnet run kassa.cs |
één los .cs-bestand uitvoeren, zonder project (sinds .NET 10) |
dotnet add package <naam> |
een pakket van NuGet toevoegen (zoals pip install) |
Voor snelle experimenten is dotnet run kassa.cs handig. Voor alles wat groter wordt maak je een project:
dotnet new console -n Kassa
cd Kassa
dotnet run
Hello, World!
In de map staan Program.cs (je code) en Kassa.csproj (de projectinstellingen, zoals de .NET-versie). Als editor kun je Visual Studio Code met de C# Dev Kit gebruiken, of JetBrains Rider.
Hello, World naast elkaar
naam = "Sanne"
print(f"Hallo {naam}!")
string naam = "Sanne";
Console.WriteLine($"Hallo {naam}!");
De verschillen die je meteen ziet:
- Elke opdracht eindigt met een puntkomma.
- De variabele heeft een type:
string. printheetConsole.WriteLine; een f-string heet hier een interpolated string en begint met$.
Typen
| Python | C# | Opmerking |
|---|---|---|
int |
int |
32 bits; voor heel grote getallen long |
float |
double |
voor metingen en berekeningen |
| — | decimal |
voor geld: rekent exact in tientallen, achtervoegsel m |
str |
string |
altijd met dubbele aanhalingstekens |
| — | char |
één teken, met enkele aanhalingstekens: 'a' |
bool |
bool |
true / false, kleine letters |
None |
null |
var
Je hoeft het type niet altijd uit te schrijven. Met var leidt de compiler het af uit de waarde:
var aantal = 3; // int
var prijs = 3.45m; // decimal
var winkel = "De Korrel"; // string
De variabele is nog steeds statisch getypeerd: aantal = "drie"; geeft een compileerfout. var scheelt alleen typen.
Getallen: let op deling en geld
Voorspel wat dit afdrukt:
Console.WriteLine(7 / 2);
Console.WriteLine(7 / 2.0);
Console.WriteLine(0.1 + 0.2);
Console.WriteLine(0.1m + 0.2m);
3
3.5
0.30000000000000004
0.3
- Twee
ints delen geeft eenint: het deel achter de komma valt weg. In Python 3 geeft7 / 2juist3.5; daar is//de gehele deling. doubleheeft dezelfde afrondingsfoutjes alsfloatin Python. Gebruik voor bedragen altijddecimal.
Strings
string product = "speltbrood";
Console.WriteLine(product.Length); // 10, een eigenschap, geen len()
Console.WriteLine(product.ToUpper()); // SPELTBROOD
Console.WriteLine(product.Contains("brood")); // True
Console.WriteLine($"{3.456m:F2}"); // 3.46 (of 3,46, zie hieronder)
Methoden beginnen in C# met een hoofdletter (ToUpper, niet upper). Achter een dubbele punt in {...} zet je een opmaak: F2 is twee decimalen, C is valuta.
Getallen worden opgemaakt volgens de taalinstelling van de computer. Op een Nederlandse Windows-pc geeft {3.46m:F2} 3,46, op een Linux-server vaak 3.46. Bij invoer werkt het net zo: decimal.Parse("3,45") hangt af van die instelling. In een webapp stel je de cultuur daarom expliciet in; dat zie je later.
Voorwaarden en lussen
if totaal >= 25:
bezorging = 0
elif totaal >= 10:
bezorging = 2.5
else:
bezorging = 3.95
for i in range(3):
print(i)
for brood in broden:
print(brood)
decimal bezorging;
if (totaal >= 25)
{
bezorging = 0;
}
else if (totaal >= 10)
{
bezorging = 2.5m;
}
else
{
bezorging = 3.95m;
}
for (int i = 0; i < 3; i++)
{
Console.WriteLine(i);
}
foreach (var brood in broden)
{
Console.WriteLine(brood);
}
- Voorwaarden staan tussen haakjes; blokken staan tussen accolades. Inspringen is alleen voor de leesbaarheid.
elifheetelse if.for (start; voorwaarde; stap)is de klassieke teller;foreachloopt over een verzameling, zoals Pythonsfor ... in.and,or,notzijn&&,||,!.
Functies (methoden)
def bereken_korting(bedrag, percentage=10):
return bedrag * percentage / 100
static decimal BerekenKorting(decimal bedrag, decimal percentage = 10)
{
return bedrag * percentage / 100;
}
// korter, voor een functie met één expressie:
static decimal BerekenKorting2(decimal bedrag, decimal percentage = 10) => bedrag * percentage / 100;
- Het teruggeeftype staat vooraan (
decimal); geeft de functie niets terug, dan is datvoid. - Elke parameter heeft een type.
- Namen schrijf je in PascalCase (
BerekenKorting), lokale variabelen in camelCase (regelTotaal). Python gebruiktsnake_case; in C# zie je dat bijna nooit. - In een los bestand mag de functie onderaan staan;
staticbetekent hier dat hij niet bij een object hoort. Klassen komen in les 06 en verder vanzelf aan bod.
List en Dictionary
broden = ["spelt", "rogge"]
broden.append("wit")
print(len(broden), broden[0])
prijzen = {"spelt": 3.45, "rogge": 3.10}
prijzen["wit"] = 2.50
if "spelt" in prijzen:
print(prijzen["spelt"])
var broden = new List<string> { "spelt", "rogge" };
broden.Add("wit");
Console.WriteLine($"{broden.Count} {broden[0]}");
var prijzen = new Dictionary<string, decimal>
{
["spelt"] = 3.45m,
["rogge"] = 3.10m,
};
prijzen["wit"] = 2.50m;
if (prijzen.TryGetValue("spelt", out var prijs))
{
Console.WriteLine(prijs);
}
List<string>lees je als "lijst van strings". Tussen< >staat het type van de elementen: een lijst bevat altijd één soort.Countin plaats vanlen().prijzen["mais"]voor een sleutel die niet bestaat, gooit eenKeyNotFoundException(zoalsKeyError).TryGetValuecontroleert en leest in één keer;ContainsKeycontroleert alleen.
null en nullable types
string? naam = null;
Console.WriteLine(naam?.Length ?? 0); // 0
Moderne C#-projecten staan nullable reference types aan. Een string mag dan geen null zijn; een string? wel. Wil je iets met een string? doen, dan waarschuwt de compiler als je niet eerst controleert. Twee handige operatoren:
naam?.Length: alsnaamnullis, is het resultaat ooknull, in plaats van een crash.x ?? 0: alsxnullis, neem dan0.
Uitgewerkt voorbeeld: een kassabon
var producten = new Dictionary<string, decimal>
{
["speltbrood"] = 3.45m,
["croissant"] = 1.20m,
["appeltaart"] = 12.50m,
};
var bestelling = new List<(string Product, int Aantal)>
{
("speltbrood", 2),
("croissant", 4),
("appeltaart", 1),
};
decimal totaal = 0;
foreach (var (product, aantal) in bestelling)
{
decimal regelTotaal = producten[product] * aantal;
totaal += regelTotaal;
Console.WriteLine($"{aantal,2} x {product,-12} {regelTotaal,8:F2}");
}
Console.WriteLine(new string('-', 26));
Console.WriteLine($"{"Totaal",-17} {totaal,8:F2}");
decimal btw = Math.Round(totaal * 9 / 109, 2);
Console.WriteLine($"{"waarvan btw 9%",-17} {btw,8:F2}");
2 x speltbrood 6.90
4 x croissant 4.80
1 x appeltaart 12.50
--------------------------
Totaal 24.20
waarvan btw 9% 2.00
Nieuwe dingen:
(string Product, int Aantal)is een tuple met namen, net als een tuple in Python.foreach (var (product, aantal) in ...)pakt hem uit.{aantal,2}maakt een kolom van 2 tekens breed, rechts uitgelijnd;{product,-12}een kolom van 12, links uitgelijnd (min-teken).- De btw zit in de prijs: 9/109 van het totaal is btw.
Typische fouten
| Melding | Oorzaak |
|---|---|
; expected |
Puntkomma vergeten |
Cannot implicitly convert type 'double' to 'decimal' |
3.45 zonder m in een decimal-berekening |
The name 'x' does not exist in the current context |
Typfout, of variabele binnen een { }-blok gemaakt en daarbuiten gebruikt |
KeyNotFoundException |
Sleutel bestaat niet; gebruik TryGetValue |
| Uitkomst 3 in plaats van 3,5 | Twee ints gedeeld |
Oefeningen
Oefening 1. Vertaal naar C#:
def is_even(n):
return n % 2 == 0
for n in range(1, 6):
if is_even(n):
print(f"{n} is even")
Modelantwoord oefening 1
for (int n = 1; n < 6; n++)
{
if (IsEven(n))
{
Console.WriteLine($"{n} is even");
}
}
static bool IsEven(int n) => n % 2 == 0;
Oefening 2. Wat is het type van x in var x = 10 / 4; en wat is de waarde?
Modelantwoord oefening 2
int, met waarde 2. Voor 2,5 schrijf je 10 / 4.0 (double) of 10m / 4 (decimal).
Oefening 3. Maak een Dictionary<string, int> met voorraad en schrijf een functie Verkoop(voorraad, product) die de voorraad met één verlaagt, of false teruggeeft als het product er niet (meer) is.
Modelantwoord oefening 3
static bool Verkoop(Dictionary<string, int> voorraad, string product)
{
if (!voorraad.TryGetValue(product, out var aantal) || aantal == 0)
{
return false;
}
voorraad[product] = aantal - 1;
return true;
}
Lab: kassabon als console-app
- Maak een console-project
Kassametdotnet new console. - Leg producten en prijzen vast in een
Dictionary<string, decimal>. - Vraag met
Console.ReadLine()om producten en aantallen tot de gebruiker een lege regel invoert; meld onbekende producten netjes. - Druk een kassabon af met uitgelijnde kolommen, totaal en het btw-bedrag (9%).
beetje check aspnet-les2
Samenvatting
- C# is statisch getypeerd: elke variabele heeft een type;
varlaat de compiler het afleiden. - Puntkomma's, accolades, haakjes om voorwaarden; methoden in PascalCase.
decimal(metm) voor geld;int / introndt naar beneden af.List<T>enDictionary<TKey, TValue>zijn de tegenhangers van list en dict;TryGetValuevoorkomt crashes.dotnet new,dotnet runendotnet add packagezijn de basiscommando's.
Volgende les: LINQ, de manier om in C# met verzamelingen te werken.
Lab
Kassabon als console-app
💻 Dit lab doe je op je eigen computer met Docker. Start de lab-container met (geeft de opdracht een eigen startcommando, gebruik dan dat):
$ docker run -it --rm registry.wizg.it/webhosting/beetje-labs:aspnet-les2
Klaar? Controleer je werk met:
$ beetje check aspnet-les2