Hoe ging het met InteliJ? Wat is een .iml bestand? Wat is de .idea map?
Hoe werkt Maven?
Wanneer is een solution handig? Voorbeelden.
Waarom zijn er verschillende programmeertalen?
Tabel met programmeertalen
Geschiedenis C#: Microsoft wilde ook een soort Java
Microsoft’s eigen Java ‘Visual J++’ was niet compatible met Sun's Java. Microsoft verloor van Sun in de rechtzaal.
‘Visual J#’ ook niets geworden.
.NET and C#, zelfde uitvinder als Turbo Pascal en Delphi
Onzin: “C# lijkt meer op C++ dan op Java”
een marketingstrategie om C++ programmeurs in de managed wereld te krijgen
de enige overeenkomsten qua syntax:
pointer manipulatie
notatie voor afgeleiden
operator overloading
geen header files, static main functie, single inheritence
Laat de TIOBE lijst zien van meest populaire talen
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace HaagseHogeschool
{
class Program
{
static void Main(string[] args)
{
string tekst = "Hallo";
Console.WriteLine(tekst);
}
}
}
package nl.haagsehogeschool;
import java.util.List;
import java.util.Scanner;
import java.util.function.*;
public class Program {
public static void main(String[] args) {
String tekst = "Hallo";
System.out.println(tekst);
}
}
In Java is het ook mogelijk om System.out te importeren.
In Python/Javascript is het heeel veel korter.
Gebruik het whiteboard om aan te geven wat er anders is en hetzelfde.
Namespaces: meerdere per bestand
Packages: directory structuur
IDE: Visual Studio voor C# vs IntelliJ voor Java
Andere methode namen: Console.WriteLine vs System.out.println
Verschillende kleurtjes (syntax highlighting)
Naming guidelines
Syntax verschillen: using vs import
Hetzelfde paradigma
De rode draad:
Heel veel hetzelfde
Kleine syntax-verschillen
En een paar grotere verschillen (asynchroon programmeren)
code conventies? camelCase methodenamen in Java, PascalCase methodenamen in C#, zie de main hier
C# is een programmeertaal die is ontworpen voor het bouwen van een breed scala aan applicaties die uitgevoerd kunnen worden op het .NET Framework. C# is eenvoudig, krachtig, type-safe en object-oriented.
Ook Java is type-safe
Dit betekent dat datatypes zoals int, double, string enz. worden gebruikt.
De compiler geeft al een foutmelding als je deze door elkaar heen haalt
Ook Java is object oriented
Je werkt met classes
Je maakt gebruik van inheritance, polymorphism en interfaces
Ook werken beide talen met references en garbage collection
https://en.wikipedia.org/wiki/Comparison_of_programming_languages#General_comparison
De .NET Runtime lijkt als 2 druppels water op Java Virtual Machine:
I.p.v. C# kun je bijv. ook VB.NET of F# gebruiken voor het .NET platform.
Wat gebeurt er als je twee objecten vergelijkt met de == operator?
Hoewel String een reference type is, zijn de vergelijkings-operatoren (== and !=) beschikbaar om de waardes (en niet de referenties!) van String-objecten met elkaar te vergelijken. Dat maakt het vergelijken van twee strings een stuk intuïtiever.
De String-class kent overigens ook een Equals en Compare methode
referenceequals
Ook C# kent exceptions
Het enige verschil is dat C# het verschil niet kent tussen checked en unchecked exceptions
De bekendste exception is: NullReferenceException
Wat heeft deze exception te maken met value en reference type?
Reminder: program code throws an Exception if a runtime error occurs
Voor private variabelen (inclusief parameters) gebruik je camelCasing
Daarnaast:
Een interface begint altijd met een hoofdletter I:
dus IComparable of IPerson
Wat is encapsulatie?
Waarom geen publieke variabelen?
public int value; vs private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; }
We kunnen extra logica toevoegen in de setter (is een andere methode-naam dan niet geschikter?)
class Vrouw {
private Man partner;
public void setPartner(Man man) {
this.partner = man;
man.setPartner(this); // voorkom oneindige loop
this.achternaam = man.achternaam;
}
}
private int temperatuur;
public void setTemperatuur(int temperatuur) {
// for listeners that prevent from calling
this.temperatuur = temperatuur;
for (listener in this.temperatuurChangedListeners())
listener.fire();
}
private Waarde waarde = null;
public Waarde getWaarde() {
if (this.waarde == null)
this.waarde = ingewikkeldeInitialisatie();
return this.waarde;
}
We kunnen nu de implementatie overriden in een afgeleide klasse (maar wees voorzichtig).
Er is niets mis met publieke final variabelen.
Over encapsulatie en information hiding: https://www.infoworld.com/article/2075271/encapsulation-is-not-information-hiding.html
niet alle setters hoeven publiek "{get; private set; }"
objecten in OO zijn geen data houders, objecten in OO exposen gedrag
C# gebruikt geen get- en set-methodes maar properties:
private int leeftijd;
public int Leeftijd
{
get
{
return leeftijd;
}
set
{
leeftijd = value;
}
}
Vaak is een auto-implemented property voldoende
public int Leeftijd { get; set; }
Maar als het nodig is, kan je ook logica in een property plaatsen
private double percentage;
public double Percentage
{
get
{
if (percentage > 100) return 100 else return percentage;
}
}
Wat gebeurt er als ik get {return Leeftijd; } doe (met een hoofdletter)?
Wij gaan het Xunit-framework gebruiken (er zijn anderen)
In Visual Studio 2019 is Xunit standaard beschikbaar als framework voor unit tests. Gebruik voor VS Code de Nuget package.
Andere unit test frameworks voor C#: TODO
Wat is een unit test?
unit is klein, meestal 1 methode van klasse
automatische test
Waarom unit testen?
nuttig voor het bewaken van de kwaliteit van je code
na iedere (kleine) wijziging kun je de code automatisch testen
voorkomt bugs in bestaande functionaliteit waarvoor de bestaande unittesten moeten blijven slagen
voor nieuwe functionaliteit moeten er nieuwe unittest bijgemaakt worden
Visual Studio
Maak in een nieuw Console App (.NET Core) project aan. In dit project zit de code die je wilt unittesten.
Voeg aan de solution met [Add] en [New Project…] een Xunit testproject (.Net Core) toe.
Add a reference to the Console App (waar de te testen code staat)
In het Xunit project, selecteer [Dependencies]
Kies met je rechter muisknop voor [Add Reference…]
Kies de naam van de net aangemaakte applicatie
using System;
namespace MijnApp
{
public class Program
{
public int GetGetal (int getal)
{
return getal;
}
...
}
}
Attributen?
De syntax:
[Depreciated] void OudeMethodeNaam() { ... }
Waarom zijn er attributen?
Attributen bieden een krachtige manier om metadataof declaratieve informatiete associëren met code (samenstellingen, typen, methoden, eigenschappen, enzovoort). Het attribuut kan runtime worden opgevraagd met behulp van een techniek die reflectie wordt genoemd.
In Java kennen we annotaties:
@Override public String toString() { ... }
Voorbeelden:
[Serializable]
public class SampleClass
{
[return:NotNull]
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static int SampleMethod([In][Out] ref double x);
}
De attributen
[Fact] geeft aan dat een methode een unittest is
Als een unit-tests op elkaar lijken, dan geven we de parameters mee in een [InlineData(...)] aan een [Theory], een “geparametriseerde ” unittest.
De methoden van Assert
True
Equal
IsType<T>
IsAssignableFrom
Throws<T>
...
Verwijs naar namespace van project!
Maak de methode een unittest met [Fact]
In :
In :
> dotnet test
Verbeter het programma nu.
using Xunit;
using MijnApp;
namespace MijnApp.Tests
{
public class UnitTest1 {
[Fact]
public void Test1()
{
Program entity = new Program();
int expected = 20;
int actual = entity.GetGetal(3, 1);
Assert.Equal(expected, actual);
}
}
}
Gebruik je creativiteit om een stukje code te schrijven met een (aantal) fout(en) en laat je medestudent daar testen voor schrijven. Zorg dat alleen de testen van de randgevallen falen. Groepjes van twee worden gemaakt en na 15 minuten bespreken we de moeilijkheden en de leukste tests.
[Theory]
[InlineData (20)]
[InlineData (40)]
public void Test2 (int value)
{
Program entity = new Program();
Assert.True(entity.getGetal(value) == value);
}
TDD = Test Driven Development
Je analyseert het probleem en kiest een oplossingsrichting
Op dat moment weet je nog niet hoe je dit probleem op gaat lossen
Maar je kent wel het gewenste gedrag van het programma:
Je weet wat je erin stopt en je weet wat eruit moet komen
Je weet alleen nog niet hoe je dat gaat realiseren (black box!)
De Black box is het Java-programma dat er misschien nog niet eens is
Als je requirements (incl. Class Diagram) klaar zijn, weet je nog niet hoe je dat gaat programmeren, maar je weet al wel wat bij een gegeven input de verwachte output zal zijn.
Projectaanpak verschuift van Waterval naar Scrum (ofwel: aan het einde van elke sprint moet een kant en klaar product opgeleverd kunnen worden dat productieklaar is getest en bij elke volgende sprint verder wordt uitgebreid).
Tegenwoordig wordt Continuous Integration gebruikt (d.w.z. dat de installatie van software geautomatiseerd wordt uitgevoerd als alle tests succesvol zijn uitgevoerd). Testen en installeren gebeurt m.a.w. niet meer met de hand, maar door een computerprogramma.
Voorbeeld van een Kassa:
Je wilt 10% korting aan klanten geven als zij minimaal 3 producten met een minimale totaalprijs van € 100,00 kopen.
Stel: ik voeg een aantal producten toe:
Product 1 met een prijs van € 50,00
Product 2 met een prijs van € 60,00
Product 3 met een prijs van € 10,00
De klant betaalt (incl. 10% korting) € 108,00.
Benoem verantwoordelijkheden voor elke klasse (analysemodel)
Specificeer de publieke interface (met paramters en returntype)
Voeg bij elk onderdeel van de interface noodzakelijk commentaar toe
Voeg de properties/attributes toe
Ontwerp en schrijf de tests
Implementeer je interface
Wat zijn de globale verantwoordelijkheden van je classes?
Het moet mogelijk zijn om een lege kassa (zonder producten) aan te maken.
Er moet een item met prijs aan de kassa toegevoegd kunnen worden.
De totaalprijs van een bestelling (incl. korting) is opvraagbaar.
De kassa moet leeg gemaakt kunnen worden voor een volgende bestelling.
In feite heb je het hier nog over je analysemodel.
Hiervoor kun je de globale operaties uit je Class Diagram gebruiken (zonder parameters en returntype).
Specificeer de publieke interface (incl. parameters en returntypes)
Voeg operaties toe aan de juiste class in je Java-programma:
class CashRegister
{
public CashRegister() {}
public void AddItem(double Price) {}
public double ComputeTotal () {}
public void Clear () {}
}
To do (pas bij stap 6): programmeer AddItem (…) etc., want die geven nu natuurlijk nog niet het juiste resultaat.
Voeg aan elke operatie minimaal noodzakelijk commentaar toe.
/* Voegt een product met prijs Price toe. */
public void AddItem(double Price) {}
/* Berekent de prijs van een bestelling (incl. korting) */
public double computeTotal () { return 0.0 }
/* CashRegister wordt geïnitialiseerd voor een
* volgende klant. */
public void Clear () {}
In je ontwerp heb je al nagedacht over noodzakelijke properties. Die voeg je nu toe in je programma.
/* Om de uiteindelijke prijs van een bestelling te
kunnen bepalen, moet o.a. het subtotaal worden
bijgehouden. */
public double Total { get; set; }
/* Om de korting op een bestelling te kunnen bepalen,
* moet het aantal producten worden bijgehouden */
public int Count { get; set; }
Bij de start moet ComputeTotal() € 0 opleveren en moet getCount() 0 als resultaat teruggeven.
Na toevoegen van een item (prijs: € 10) levert ComputeTotal() € 10 op en Count geeft 1 terug.
Na nog een item (prijs: € 20) levert ComputeTotal() € 30 op en Count geeft 2 terug.
Nog een item (prijs: € 20), levert ComputeTotal() € 50 op en Count geeft 3 terug (LET OP: zonder korting, want totaalprijs is nog lager dan € 100,00).
Opnieuw een item (prijs: € 60), levert ComputeTotal() € 99 op en Count geeft 4 terug (LET OP: nu wel met korting!!!).
Na Clear() moet ComputeTotal() € 0 opleveren en moet Count 0 als resultaat teruggeven.
Implementeer de methodes en voer de tests net zolang uit tot alle tests het gewenste resultaat opleveren.
Het voordeel van deze aanpak:
e programmeert de tests zodra je deze kunt maken.
Je hoeft de implementatie van de classes nog niet te kennen.
Je hoeft de tests maar één keer te schrijven en kunt ze telkens herhalen.
Kleine aanpassingen kun je op het niveau van tests snel doorvoeren.
Dat is niet alleen handig voor Continuous Integration, maar ook als je Refactoring (aanpassing) van je code doorvoert.
Bij elke verandering: vul je de tests aan, als de interface wordt uitgebreid of aangepast.
Doe de challenges in Stepik voor Java, nu in C#.
Doe de challenges in Stepik voor Java, nu in C#.