C# voor een Java-programmeur
Met mijn indiensttreding bij Infi per 1 juni 2020 wisselde ik niet alleen van werkgever, maar ook van programmeertaal. Na 17 jaar Java (en recent natuurlijk ook Kotlin) gebruikt te hebben voor de backend, kwam ik nu in een project, waar C# gebruikt werd. Vol goede moed aan de slag, want van de ene objectgeoriënteerde programeertaal naar de andere: Hoe moeilijk kan het zijn?
Een heel nieuw eco-system.
Zo’n overstap naar een andere taal gaat natuurlijk niet alleen over de taal zelf, maar ook alles er omheen: – Coding Conventions – Libraries – Runtime Environment – Build tools – Deployment Automation
Bij deze een kleine retrospective op 5 maanden C#.
C# vs .NET
Vanuit Java kende ik al het verschil tussen de programmeertaal, die voldoet aan de Java Language Specification en de runtime, die voldoet aan de Java Virtual Machine Specification, In de .NET wereld hebben deze verschillende aspecten ook verschillende namen, die dit minder verwarrend maken. Je hebt C# als programmeer taal en .NET Core als runtime. Net zo als Java naar bytecode wordt gecompileerd, zo wordt C# code gecompileerd naar CIL (Common Intermediate Language). De .NET Core runtime kan dan gebruikt worden voor het uitvoeren van het programma. Er zijn nog meer talen, zoals F# of Visual Basic, die ook naar CIL gecompileerd kunnen worden en er zijn ook nog andere runtimes, zoals Xamarin/Mono.
Project structuur
Een C#-project wordt gevat in een ‘Solution’, welke uit verschillende Projecten
kan bestaan. Dit is vergelijkbaar met een Multi-Module Project van Maven
, waarbij het verschil is dat de projecten in C# niet van elkaar overerven. Uiteraard kunnen ze wel dependencies op elkaar hebben als ProjectReference
.
Ieder project definieert zelf de source version en target version door middel van het zetten van de LangVersion
en TargetFramework
.
<PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <LangVersion>7.3</LangVersion> </PropertyGroup>
Testen in de project structuur
Één groot verschil is de structuur is dat bij C# de Testen in een specifiek Test-project zitten in plaats van in een aparte directory binnen het project, zoals bij maven
gebruikelijk is. Dit Test-project heeft dan dus een dependency op het project of de projecten met de productie-code.
Qua structuur zou je er voor kunnen kiezen om voor ieder project met productiecode ook 1 project te maken met de Test voor dat project, maar dat is niet per se de conventie
De taal zelf
Java en C# lijken in de basis behoorlijk op elkaar qua de structuur classes, interfaces, methoden, fields en operators. Zowel de rekenkundige operatoren als de Booleaanse logische operatoren zijn exact hetzelfde en ook de syntax voor if
, for
-loops, switch
-statements zijn gelijk.
Indien een class een andere class extends of een interface implementeert, in beide gevallen wordt dat aangegeven na een :
achter de classnaam zoals: public abstract class Controller : ControllerBase, IActionFilter, IAsyncActionFilter, IDisposable
. Je kunt het verschil niet zien, behalve dat de ‘I’-prefix bij interfaces wel een behoorlijke indicator is. Die I
is niet verplicht, maar wel onderdeel van de standaard Naming Guidelines
Enums
Wat wel echt anders is, dat zijn de enums. In C# definieert een Enum een set van constante namen voor onderliggende numerieke waarden. De onderliggende waarde zijn standaard int
s en worden automatisch genummerd vanaf 0. Je mag echter ook zelf een waarde toewijzen aan individuele constanten of een andere numeriek type kiezen.
De enum kan dus niet een gehele datastructuur representeren.
Een ander gevolg van deze implementatie, merk je voornamelijk bij het switch
-statements, waar alsnog een default
moet worden toegevoegd, zelfs als alle opties van de Enum als case
voorkomen.
LINQ
Met behulp van ‘Language Integrated Query’ (LINQ) wordt het mogelijk om op een uniforme manier queries te doen tegen een datasources. Zo’n datasource kan bijvoorbeeld een XML-bestand, SQL-databases of in memory collecties zijn. De beschikbare keywords hiervoor zijn duidelijk afgeleid van SQL met termen zoals: select
, from
, where
, join
, group
en orderby
.
Het werkt met IEnumerable<T>
en daardoor lijkt het qua gedrag allemaal behoorlijk zoals de Java Streams API of Kotlin Collections, waarbij de namen in lijn zijn met SQL en dus niet met standaard namen uit de ‘functionele’ paradigma zoals map
en filter
.
Wil je wel liever met dergelijke namen werken, dan kun je ondersteuning daarvoor toevoegen vanuit: LanguageExt
Struct
Met struct heeft C# wel al een echt Value Type aanboord. Qua gedrag lijken dergelijke structs op Records uit Java 14 of Kotlin Data Classes, zeker als de struct readonly
worden gemaakt. Echter als echt Value Type leven de struct
s dus op de stack.
Code style
Zodra je C#-code gaat lezen als Java-programmeur, dan vallen er meteen een paar dingen op:
- De Properties van een Class worden met PascalCasing geschreven, dus een kledingstuk heeft
private Color Color
ipvprivate Color color
. - De accolade voor het openen van een nieuw blok
{
staat op de volgende regel.
Daar waar in de Java wereld CheckStyle de tool is voor statisch code analyse, zo zijn er de StyleCopAnalyzers voor .NET.
Conclusie
Als Java programmeur kun je best wel snel redelijk productief worden op een C#-project, maar alle details onder knie krijgen duurt wel iets langer