Assemblies in C#

  1. Inleiding
  2. build
  3. executable
  4. dynamic link library
  5. csc.exe
  6. Voorbeeldprogramma
  7. Compileren met csc.exe
  8. Resultaat
  9. ildasm / MSIL
  10. 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.

up | down

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.

up | down

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.

up | down

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.

up | down

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.

up | down

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";
      }
    }
  }     
}

up | down

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

up | down

Resultaat

We starten de Windows Command file (.cmd) en na het compileren wordt vanuit de .cmd het gecompileerde meteen opgestart. We krijgen dit resultaat:

up | down

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)
    .
    .
    . 
    .

up | down

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…


up

Laat een reactie achter

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *