Assemblies in C#
- Inleiding
- build
- executable
- dynamic link library
- csc.exe
- Voorbeeldprogramma
- Compileren met csc.exe
- Resultaat
- ildasm / MSIL
- Slot
Inleiding
In deze post gaan we het hebben over assemblies. Een assembly kan of een dynamic link library (.dll) of een executable (.exe) zijn. Het idee achter de dynamic link library is dat deze door meerdere programma’s gebruikt kan worden zodat code niet gedupliceerd hoeft te worden. We laten zien hoe we met csc.exe (de csharpcommandline compiler) dynamic link libraries en executables kunnen maken waarbij de .exe gebruik maakt van de dynamic link libraries.
build
In de posting over conditioneel compileren hadden we het gehad over een build. Een build bevat MSIL (Microsoft Intermediate Language) welke door een compiler uit de (C#) broncode werd gegenereerd. In de posting zagen we hoe we met ildasm de MSIL broncode van de build konden bekijken.
executable
De build / assembly die we in de post over conditioneel compileren hadden bekeken was een executable (.exe). De JIT compiler van het .NET Framework ziet een .exe (Windows operating system) als een uitvoerbaar programma en zorgt ervoor dat de .exe wordt omgezet naar machinecode waarna de machinecode direct wordt uitgevoerd.
dynamic link library
Een build / assembly kan ook een dynamic link library zijn (.dll). Een .dll (Windows operating system) is niet bedoeld als een direct uitvoerbaar programma, maar als een bibliotheek (library) met allerlei functies. De library wordt geladen zodra een door de JIT compiler opgestart uitvoerbaar programma dingen van die library nodig heeft. Het is de bedoeling dat een .dll door meerdere programma’s wordt gebruikt. Je wilt ten slotte zo min mogelijk code dupliceren en zo veel mogelijk code hergebruiken.
csc.exe
De Microsoft .NET Framework Software Development Kit (SDK) bestaat uit een aantal tools en dIe tools worden ook door de Visual Studio IDE gebruikt. De tools kunnen ook los van Visual Studio opgestart worden. We roepen in dit voorbeeld csc.exe (de csharpcommandline compiler) direct aan en niet indirect via de Visual Studio IDE.
Voorbeeldprogramma
We beginnen met een hoofdprogramma waarvan de C# broncode in een bestand staat met de naam main.cs. main.cs wordt gecompileerd naar een .exe. Het hoofdprogramma maakt verder gebruik van een aantal methodes uit een aantal klassen die staan in een library met de naam bibliotheek. Het voorbeeldprogramma moet het resultaat geven dat je een “getrouwde meerderjarige man bent.“
using System;
using bibliotheek;
namespace Hoofdprogramma
{
class Klasse
{
public static void Main()
{
Console.WriteLine("Over jou:");
// Volwassen?
Console.WriteLine(
"- Je bent {0}",
Volwassen.Bepaal(28));
// Huwelijkse staat
Console.WriteLine(
"- Je bent {0}",
HuwelijkseStaat.Bepaal('G'));
// Geslacht
Console.WriteLine(
"- Je bent een {0}",
Geslacht.Bepaal('M'));
// Gezien?
Console.WriteLine(
"Druk op een willekeurige
toets om verder te gaan...");
Console.ReadKey();
}
}
}
We hebben een klasse Volwassen met een methode bepaal en de broncode staat in een bestand met de naam volwassen.cs. volwassen.cs wordt gecompileerd naar een .dll.
namespace bibliotheek
{
public static class Volwassen
{
public static string Bepaal(int leeftijd)
{
if (leeftijd < 18)
{ return "Minderjarig";}
else
{ return "Meerderjarig";}
}
}
}
We hebben naast klasse Volwassen ook een klasse HuwelijkseStaat met een methode bepaal en de broncode staat in een bestand met naam staat.cs. staat.cs wordt ook gecompileerd naar een .dll:
namespace bibliotheek
{
public static class HuwelijkseStaat
{
public static string Bepaal(char code)
{
switch (code)
{
case 'S': return "Single";
case 'G': return "Getrouwd";
default: return "Onbekend";
}
}
}
}
En we hebben ten slotte ook een klasse Geslacht met een methode bepaal en de broncode staat in een bestand met de naam geslacht.cs. Ook geslacht.cs wordt gecompileerd naar een .dll:
namespace bibliotheek
{
public static class Geslacht
{
public static string Bepaal(char code)
{
switch (code)
{
case 'M': return "Man";
case 'V': return "Vrouw";
default: return "Onbekend";
}
}
}
}
Compileren met csc.exe
We maken een Windows Command file (.cmd) waarin csc.exe alles compileert en ervoor zorgt dat het hoofdprogramma de functies van de afzonderlijke .dll bestanden kan terugvinden in een library met de naam Bibliotheek:
@echo off
cls
echo Compileer volwassen.cs
REM naar .dll
"C:\csc"
/t:library
/out:C:\assemblies\volwassen.dll
"C:\assemblies\volwassen.cs"
echo Compileer staat.cs
REM naar.dll
"C:\csc"
/t:library
/out:C:\assemblies\staat.dll
"C:\assemblies\staat.cs"
echo Compileer geslacht.cs
REM naar.dll
"C:\csc"
/t:library
/out:C:\assemblies\geslacht.dll
"C:\assemblies\geslacht.cs"
echo compileer met losse dll
REM link de .dll-bestanden
REM en maak er programma.exe van
"C:\csc"
C:\main.cs
/t:exe
/r:
C:\assemblies\staat.dll;
C:\assemblies\geslacht.dll;
C:\assemblies\volwassen.dll
/out:C:\assemblies\programma.exe
echo Start het gecompileerde programma
C:\assemblies\programma
Resultaat
We starten de Windows Command file (.cmd) en na het compileren wordt vanuit de .cmd het gecompileerde meteen opgestart. We krijgen dit resultaat:
ildasm / MSIL
Als we met ildasm programma.exe bekijken dan zien we dat er verwijzingen zijn naar library Bibliotheek en naar de assemblies waarin de te gebruiken functies staan:
// Microsoft (R) .NET Framework IL Disassembler.
// Copyright (c) Microsoft Corporation.
// All rights reserved.
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly extern volwassen
{ .ver 0:0:0:0 }
.assembly extern staat
{ .ver 0:0:0:0 }
.assembly extern geslacht
{ .ver 0:0:0:0 }
// ==== CLASS MEMBERS DECLARATION ====
.class private auto ansi
beforefieldinit Hoofdprogramma.Klasse
extends [mscorlib]System.Object
{
.method public hidebysig
static void Main() cil managed
{
.entrypoint
// Code size 84 (0x54)
.maxstack 2
IL_0000: nop
IL_0001: ldstr "Over jou:"
IL_0006: call void [mscorlib]
System.Console::
WriteLine(string)
IL_000b: nop
IL_000c: ldstr "- Je bent {0}"
IL_0011: ldc.i4.s 28
IL_0013: call string [volwassen]
bibliotheek.Volwassen::
Bepaal(int32)
IL_0018: call void [mscorlib]
System.Console::
WriteLine(string, object)
.
.
.
.
Slot
We hebben in dit voorbeeld drie .dll assembly bestanden gemaakt (volwassen.dll, staat.dll en geslacht.dll) waarbij de .dll bestanden niet alleen door assembly programma.exe gebruikt kunnen worden, maar ook door andere programma’s.
We hebben nu zo’n beetje een pre .NET tijdperk set up. Het werkt allemaal wel, maar deze set up geeft nogal eens issues voor wat betreft versiebeheer (de “DLL Hell”) en beveiliging (hoe weet je dat niet stiekem is geknoeid met de dll-bestanden).
Hopelijk ben je met deze posting weer wat wijzer geworden en ik hoop je weer terug te zien in één van mijn volgende blog posts. Wil je weten wat ik nog meer over C# heb geschreven? Hit the C# button…