Laden von Klassen zur Laufzeit

Veröffentlicht: 11. Dez 2002 | Aktualisiert: 21. Jun 2004

Von Billy Hollis

Wie können sie .NET erweitern? Dieser Frage geht der Autor Billy Hollis nach und zeigt, wie Sie in Ihren Visual-Basic-Anwendungen Klassen mithilfe des System.Reflection-Namespace dynamisch laden können. Das geht selbst dann, wenn Sie zum Zeitpunkt der Übersetzung nicht wissen, welche zur Laufzeit Klasse geladen wird.

Auf dieser Seite

 Ein typisches Szenario
 Laden von anderen Klassentypen zur Laufzeit
 Schlussfolgerung

Laden Sie die Beispieldatei "VBNETDynamicForms.exe" aus dem MSDN Code Center. Bitte beachten Sie, dass die Kommentare der Programmierer in den Beispieldateien englischsprachig sind. Zum leichteren Verständnis wurden sie in diesem Artikel übersetzt.

Wäre die Welt perfekt, würden wir alle Anforderungen an ein Softwaresystem kennen, bevor wir es schrieben. Aber da wir nun einmal nicht in einer perfekten Welt leben, müssen unsere Systeme anpassbar sein.

Die äußerste Form der Anpassungsfähigkeit ist die Möglichkeit, neue Funktionen zur Laufzeit zu integrieren. Für eine Windows-Forms-Anwendung bedeutet das zum Beispiel die Fähigkeit, neue Formulare zu laden, die lange nach der Kompilierung der ursprünglichen Anwendung erstellt wurden.

Dieser Vorgang war in Microsoft Visual Basic 6.0 nahezu unmöglich, in Visual Basic .NET ist es aber ziemlich einfach. Indem das Programm sich die Fähigkeiten des System.Reflection-Namespace zunutze macht, kann das Laden von Assemblies zur Laufzeit angefordert werden; es muss einfach der Pfad der Assembly bekannt sein. Es können dann Klassen von der Assembly geladen und instanziert werden.

Da ein Windows-Formular einfach eine weitere Klasse ist, bedeutet dies, dass Formulare zur Laufzeit geladen, angezeigt und verwendet werden können, auch wenn sie bei der Kompilierung der ursprünglichen Anwendung noch nicht existierten.

Ein typisches Szenario

Nehmen wir an, wir haben eine MDI-Anwendung (Multiple Document Interface - Mehrfache Dokumentschnittstelle), die über die Fähigkeit verfügen soll, beliebige Formulare als untergeordnete Formulare zu laden. Die Anwendung muss Folgendes ausführen können:

  • Abrufen einer Liste von Formularen, die zum Laden verfügbar sind, i.d.R. aus einer .NET-Konfigurationsdatei.

  • Anzeigen der Liste und die Möglichkeit der Auswahl eines Formulars für den Benutzer.

  • Instanziieren und Anzeigen des Formulars, das der Benutzer ausgewählt hat.

Lassen Sie uns ein Programm hierfür schreiben und ansehen, wie dynamisches Laden funktioniert.

Schritt 1: Erstellen Sie das Projekt und das MDI-Formular
Starten Sie ein neues Windows-Forms-Projekt. Nennen Sie es FormsOnTheFly. Ändern Sie die IsMdiContainer-Eigenschaft des leeren Formulars Form1 in dem neuen Projekt zu TRUE. Das MDI-Formular ist jetzt übergeordnet. Skalieren Sie nun die Formulargröße auf ungefähr die doppelte Länge und Höhe.

Ziehen Sie ein Panel-Steuerelement auf das Formular, und definieren Sie die Dock-Eigenschaft des Steuerelements, um es oben im Formular anzudocken. Skalieren Sie die Panel-Fläche auf eine Höhe von ungefähr 4 cm.

Ziehen Sie ein ComboBox-Element auf die Fläche. Nennen Sie das Kombinationsfeld cboForms, und definieren Sie die DropDownStyle-Eigenschaft als DropDownList.

Ziehen Sie zum Schluss ein Button-Steuerelement auf die Fläche. Nennen Sie die Schaltfläche btnLoadForm, und legen Sie Load Form als Text-Eigenschaft fest.
Form1 sollte jetzt in etwa Abbildung 1 gleichen.

Bild01

Abbildung 1. Das MDI-Formular im Entwurfsmodus nach dem Platzieren aller Steuerelemente

Schritt 2: Erstellen Sie eine Klasse, die Daten über verfügbare Formulare enthält
Die Informationen über die verfügbaren Formulare werden wir aus einer XML-basierten Konfigurationsdatei auslesen. Wir erstellen aber eine Auflistung von Objekten, um die Anzeige von verfügbaren Formularen im Kombinationsfeld und das Abrufen von Informationen über ein ausgewähltes Formular zu erleichtern. Jedes Objekt in der Auflistung enthält die Informationen über ein mögliches Formular. Das Objekt muss über die folgenden Eigenschaften verfügen:

  • Description: die Beschreibung des Formulars, die im Kombinationsfeld angezeigt wird

  • Location: der Dateiname der DLL, in der sich das Formular befindet

  • Type: der Name des .NET-Typs des Formulars (zum Beispiel MyProject.Form1)

Solch eine Auflistung kann an ein Listenfeld datengebunden sein (weitere Informationen hierzu unter Not Your Father's DatabindingHier verlassen Sie die Website von Microsoft Deutschland [in Englisch]). Um einen Verweis vom Listenfeld an das ausgewählte Objekt zurückzugeben, benötigen wir eine zusätzliche Eigenschaft, die wir Reference nennen.

Wählen Sie zum Erstellen der Klasse Projekt | Klasse hinzufügen, und nennen Sie die Klasse DynamicClass.vb. Platzieren Sie in der Klasse den folgenden Code:

Public Class DynamicClass
    Dim msLocation As String
    Dim msType As String
    Dim msDescription As String
    Public Sub New(ByVal sLocation As String, _ 
                   ByVal sDescription As String, _
                   ByVal sType As String)
        Me.Location = sLocation
        Me.Description = sDescription
        Me.Type = sType
    End Sub
    Public Property Location() As String
        Get
            Return msLocation
        End Get
        Set(ByVal Value As String)
            msLocation = Value
        End Set
    End Property
    Public Property Type() As String
        Get
            Return msType
        End Get
        Set(ByVal Value As String)
            msType = Value
        End Set
    End Property
    Public Property Description() As String
        Get
            Return msDescription
        End Get
        Set(ByVal Value As String)
            msDescription = Value
        End Set
    End Property
    Public ReadOnly Property Reference() As Object
        Get
            Return Me
        End Get
    End Property
End Class

Schritt 3: Erstellen Sie eine Konfigurationsdatei, die die verfügbaren Formulare enthält
Wenn eine Anwendung zur Laufzeit Informationen benötigt, die zum Zeitpunkt der Kompilierung nicht zur Verfügung stehen, werden die Informationen normalerweise in eine Konfigurationsdatei platziert. In Visual Basic 6.0 wäre dies eine INI-Datei oder die Windows-Registrierung gewesen. In .NET wird eine XML-basierte Konfigurationsdatei verwendet.

Wir können das komplexe Thema Konfigurationsdateien hier nicht im Detail behandeln, aber Sie sollten wissen, dass die Konfigurationsdatei einer Windows-Forms-Anwendung sich im gleichen Verzeichnis befindet wie die EXE-Startdatei der Anwendung. Der Name ist identisch mit dem der EXE-Datei, mit angehängtem Suffix .config. Wenn meine Anwendung also durch die Datei MyApp.exe gestartet wird, muss die Konfigurationsdatei MyApp.exe.config heißen und sich in demselben Verzeichnis wie MyApp.exe befinden.

Für unser Beispiel verwenden wir die folgende Konfiguration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <section name="availableclasses" type="System.Configuration.NameValueSectionHandler" />
   </configSections>
   <availableclasses>
      <add key="Placeholder - do not load" 
           value="DLLPathnameGoesHere~NameOfTypeGoesHere"></add>
      </availableclasses>
</configuration>

Zu diesem Zeitpunkt enthält das <availableclasses>-Tag nur Platzhalterinformationen, damit Sie das Format sehen. Wir werden später darauf zurückkommen und Konfigurationsinformationen über neue Formulare hinzufügen, die erstellt wurden.

Eigentlich ist dies nicht die beste Methode, um Konfigurationsinformationen für die Formulare zu speichern, da wir ein begrenztes Format zum Speichern des DLL-Pfads und des Typnamens am gleichen Ort verwenden. Ein besserer Weg, um sie getrennt zu speichern, würde aber einiges mehr an Erklärungen und Code erfordern, so dass wir uns mit dieser kleinen Mogelei begnügen.

Erstellen Sie in einem Text-Editor oder einem XML-Editor (oder Microsoft Visual Studio) die oben aufgeführte Konfigurationsdatei, und speichern Sie sie im Projekt FormsOnTheFly im Verzeichnis \bin als FormsOnTheFly.exe.config. Achten Sie beim Erstellen der Datei auf die richtige Groß- und Kleinschreibung der XML-Tags, da .NET-Konfigurationsklassen XML-Tags mit Groß- und Kleinschreibung verwenden.

Schritt 4: Lesen Sie die Konfigurationsinformationen in eine Auflistung ein
Unser Code für das Formular verwendet Klassen aus den Namespaces System.Configuration und System.Reflection. Platzieren Sie die folgenden zwei Zeilen ganz oben in den Code in Form1, um den Zugriff auf diese Klassen zu erleichtern:

Imports System.Configuration
Imports System.Reflection

Wir benötigen außerdem eine Variable auf Modulebene, um unsere Auflistung von Konfigurationsinformationen zu speichern. Platzieren Sie die folgende Zeile genau unter die Zeile, die Inherits System.Windows.Forms.Form enthält:

Dim colAvailableClasses As ArrayList

Jetzt können wir den eigentlichen Code schreiben. Platzieren Sie den folgenden Code in das Form-Load-Ereignis von Form1, um die Konfigurationsdatei zu lesen, erstellen Sie eine Auflistung von Objekten, die die Informationen enthalten, und binden Sie die Daten der Auflistung an das ComboBox-Steuerelement:
'Die Auflistung für die Konfigurationsinformationen instanziieren.

colAvailableClasses = New ArrayList()
' Verfügbare Elemente aus der Konfigurationsdatei abrufen.
Dim ClassConfigValues As Specialized.NameValueCollection
ClassConfigValues = CType(ConfigurationSettings.GetConfig("availableclasses"), _ 
    Specialized.NameValueCollection)
Dim iIndex As Integer
Dim sLocation As String
Dim sDescription As String
Dim sType As String
Dim sValue As String
' Auflistung verfügbarer Elemente für die
' Bindung an ein Kombinationsfeld erstellen.
For iIndex = 0 To ClassConfigValues.Count - 1
    sDescription = ClassConfigValues.Keys(iIndex)
    sValue = ClassConfigValues.Item(sDescription)
    ' Ein kleiner Trick, um Pfad
    ' und Typ aus einem Feld abzurufen.
    Dim iPos As Integer
    iPos = InStr(sValue, "~")
    sLocation = Microsoft.VisualBasic.Left(sValue, iPos - 1)
    sType = Microsoft.VisualBasic.Right(sValue, Len(sValue) - iPos)
    Dim objNewForm As New DynamicClass(sLocation, sDescription, sType)
    colAvailableClasses.Add(objNewForm)
Next
' Jetzt wird die Auflistung an das Kombinationsfeld gebunden. 
' Die Beschreibung wird angezeigt und
' ein Verweis auf das Objekt zurückgegeben.
cboForms.DataSource = colAvailableClasses
cboForms.DisplayMember = "Description"
cboForms.ValueMember = "Reference"

Schritt 5: Fügen Sie die Logik zum Laden eines ausgewählten Formulars ein
Platzieren Sie die folgende Logik in das click-Ereignis für btnLoadForm:

Dim objFormToLoad As DynamicClass
objFormToLoad = cboForms.SelectedValue
Dim asmAssemblyContainingForm As [Assembly] = _
    [Assembly].LoadFrom(objFormToLoad.Location)
Dim TypeToLoad As Type = asmAssemblyContainingForm.GetType(objFormToLoad.Type)
Dim GenericInstance As Object
GenericInstance = Activator.CreateInstance(TypeToLoad)
Dim FormToShow As Form = CType(GenericInstance, Form)
FormToShow.MdiParent = Me
FormToShow.Show()

Dies ist das Herzstück des Programms. Dieser Code instanziert und zeigt ein Formular, indem er Informationen aus einem Objekt in der Auflistung verwendet. Lassen Sie uns den Code Zeile für Zeile durchgehen.

Zuerst haben wir einen Verweis auf ein Objekt (objFormToLoad), das den Pfad und den Typ des Formulars enthält, das wir laden möchten. Das Objekt wird als SelectedValue-Eigenschaft des ComboBox-Steuerelements festgelegt. Diese Eigenschaft wird verwendet, um eine Auswahl aus einem datengebundenen ComboBox-Element zurückzugeben.

Das Objekt enthält in der Location-Eigenschaft den Pfad der DLL. Mithilfe dieser Eigenschaft wird unter Verwendung der LoadFrom-Methode der Assembly-Klasse ein Verweis auf die Assembly erstellt. (Die Assembly-Klasse wird eingeklammert, da Assembly ein .NET-Schlüsselwort ist. Durch die Klammern weiß der Compiler, dass nicht das Schlüsselwort, sondern der Klassenname verwendet wird.)

Als Nächstes benötigen wir einen Verweis auf den .NET-Typ (die Klasse), die geladen wird. Hierfür wird die GetType-Methode der Assembly verwendet, indem eine Zeichenfolge übergeben wird, die den Namen des Typs enthält (der aus der Type-Eigenschaft des Objekts abgerufen wird, das die Konfigurationsdaten enthält). Der Verweis auf den Typ wird in TypeToLoad gespeichert.

Eine weitere Reflection-Klasse, die Activator-Klasse, verwendet dann die entsprechende CreateInstance-Methode, um eine Instanz des Typs zu erstellen. (CreateInstance erinnert an CreateObject in Visual Basic 6.0.) Die Instanz muss aber vom Typ Object sein, da der Typ zur Laufzeit geladen wird.

Zum Schluss muss das neu instanzierte Objekt (das tatsächlich ein Formular ist) in den richtigen Typ umgewandelt werden, um eine frühe Bindung zu ermöglichen. Da wir wissen, dass es ein Formular ist, können wir es mithilfe der CType-Funktion in diesen Typ umwandeln.

Wir setzen dann das neue Formular als ein untergeordnetes Element des übergeordneten MDI-Formulars fest und zeigen es an.

Wenn Sie Death of the Browser?Hier verlassen Sie die Website von Microsoft Deutschland (in Englisch) gelesen haben, könnte Ihnen dieser Code bekannt vorkommen. Die Logik ist der für die Internetweitergabe von Anwendungen sehr ähnlich. Wenn Ihnen die Erklärung oben nicht ausreicht, finden Sie ausführlichere Informationen unter Death of the Browser?Hier verlassen Sie die Website von Microsoft Deutschland (in Englisch).

Anmerkung Assemblies, die von einem URL geladen werden, wie in Death of the Browser?Hier verlassen Sie die Website von Microsoft Deutschland (in Englisch) dargestellt, werden in einen lokalen Zwischenspeicher kopiert. Assemblies, die von einem UNC geladen werden, wie in diesem Artikel, werden einfach an ihrem Platz verwendet und nicht in einen Zwischenspeicher kopiert.

Schritt 6: Kompilieren Sie die Anwendung
Wir können jetzt die Anwendung kompilieren, aber keine Formulare anzeigen, da noch keine erstellt wurden. Wir können das Programm kompilieren und ausführen, um zu testen, ob es funktioniert und ob das ComboBox-Steuerelement richtig mit dem Platzhalterelement geladen wird. Wenn Sie auf btnLoadForm klicken, erhalten Sie natürlich einen Fehler, da die Informationen in der Konfigurationsdatei noch nicht auf etwas verweisen.

Schritt 7: Erstellen Sie die Anzeigeformulare
Starten Sie jetzt eine neue Windows Forms-Anwendung namens FirstForm. Platzieren Sie einige beliebige Steuerelemente auf dem angezeigten leeren Form1.

Klicken Sie jetzt im Projektmappen-Explorer mit der rechten Maustaste auf FirstForms, und wählen Sie Eigenschaften. Wählen Sie im Kombinationsfeld Ausgabetyp die Option Klassenbibliothek aus. (Wenn dieses Kombinationsfeld nicht angezeigt wird, haben Sie vermutlich im Projektmappen-Explorer auf die Projektmappe und nicht auf das Projekt geklickt.)

Erstellen Sie jetzt das Projekt. Dadurch wird eine DLL erstellt, die das Formular enthält.

Legen Sie einen Ordner an, und nennen Sie ihn C: ewForms. Kopieren Sie FirstForms.dll aus dem \bin-Verzeichnis im FirstForms-Projekt in den Ordner C: ewForms.

Wiederholen Sie diese Schritte mit zwei weiteren Projekten namens SecondForm und ThirdForm. Variieren Sie die Steuerelemente, die Sie auf die einzelnen Formulare ziehen, damit Sie sie unterscheiden können. Ändern Sie zur besseren Unterscheidung auch die Hintergrundfarbe der Formulare.

Schritt 8: Aktualisieren Sie die Konfigurationsdatei mit den neuen Formularinformationen
Wir haben jetzt einige neue Formulare und möchten in der Konfigurationsdatei auf sie verweisen. Ersetzen Sie die Platzhalterinformationen in FormsOnTheFly.exe.config durch die folgenden Zeilen:

    <add key="First Form" 
           value="C: ewForms\FirstForm.dll~FirstForm.Form1"></add>
      <add key="Second Form" 
           value="C:
ewForms\SecondForm.dll~SecondForm.Form1"></add>
      <add key="Third Form"
           value="C:
ewForms\ThirdForm.dll~ThirdForm.Form1"></add>

Falls Sie die Pfadangaben oder Dateinamen geändert haben, müssen Sie diese Zeilen entsprechend anpassen.

Schritt 9: Führen Sie "FormsOnTheFly.exe" aus, und laden Sie einige Formulare
Führen Sie jetzt FormsOnTheFly.exe aus (ohne Visual Studio zu laden). Wählen Sie im Kombinationsfeld ein Formular aus, und klicken Sie auf btnLoadForm. Wenn alle Schritte richtig ausgeführt wurden, wird das untergeordnete Formular in das MDI-Fenster geladen, obwohl dieses Formular noch nicht vorhanden war, als die MDI-Anwendung kompiliert wurde.

Abbildung 2 zeigt ein Beispiel eines MDI-Formulars mit Formularen, die zur Laufzeit geladen wurden.

Bild02

Abbildung 2. Das MDI-Formular mit Formularen, die zur Laufzeit geladen wurden

Sie können jetzt so viele neue Formulare erstellen, wie Sie möchten, um sie in die MDI-Anwendung zu laden. Um die Formulare zur Verfügung zu stellen, müssen Sie sie lediglich in eine Klassenbibliothek kompilieren und in der Konfigurationsdatei auf sie verweisen.

 

Laden von anderen Klassentypen zur Laufzeit

Diese Vorgehensweise funktioniert nicht nur mit Formularen, sondern auch mit anderen Klassentypen. Es gibt dabei nur eine Schwierigkeit. Im Beispiel oben war eine frühe Datenbindung an die System.Windows.Forms.Form-Klassenschnittstelle möglich, da wir wussten, dass die Klasse ein Formular war. Wir konnten daher beispielsweise die Show-Methode des Formulars verwenden. An welche Schnittstelle können wir bei unseren eigenen Klassen binden?

Die Antwort darauf ist, unsere eigene Schnittstelle zu erstellen. Tatsächlich ist dies hier geradezu ein Paradebeispiel für das Implementieren einer Schnittstelle. Möglicherweise haben Sie in Visual Basic 6.0 bereits Schnittstellen verwendet. Sie wurden als leere Klassen gestaltet. In Visual Basic .NET gibt es eine neue Syntax, und eine Schnittstelle wird vollkommen getrennt von einer Klasse deklariert. Wie das funktioniert, sehen wir unten in Schritt 1.

Lassen Sie uns das anhand eines Beispiels erläutern, in dem das Laden einer Klasse zur Laufzeit wünschenswert ist. Wir möchten eine Anwendung zur Datenmanipulation schreiben, die ein DataSet verändert. Allerdings scheint dieses Programm, wie alle Programme zur Datenmanipulation, nie ein Ende zu finden. Immer scheint es neue Typen von Validierung und Manipulation zu geben, die codiert werden müssen.

Natürlich können Sie diese neue Logik erstellen und die ganze Anwendung neu kompilieren, aber wäre es nicht viel besser, wenn Sie die neuen Fähigkeiten zur Laufzeit ergänzen könnten, ohne die Hauptanwendung neu zu kompilieren? Das folgende Beispiel, das wir von Anfang bis Ende durcharbeiten, ermöglicht genau das.

Schritt 1: Erstellen Sie die Klassendatei, die die Schnittstelle enthält
Das Erstellen einer Schnittstelle in Visual Basic .NET ist zwar vom Konzept her vergleichbar mit der Vorgehensweise in Visual Basic 6.0, aber die Syntax ist grundverschieden. Legen Sie ein neues Projekt vom Typ Klassenbibliothek an, um die Ursprungsschnittstellenklasse zu erstellen. Geben Sie ihr den Namen ScrubberInterface.

In der angezeigten Klassendatei ersetzen Sie die vorhandenen Zeilen durch diesen Code:

Public Interface IScrubber
    Sub Scrub(ByVal ds As DataSet)
End Interface

Unsere Schnittstelle ist sehr einfach. Wir benötigen eine Methode, um Operationen für das DataSet auszuführen. Die Methode haben wir Scrub genannt.

Wenn Sie jetzt das Projekt compilieren, finden Sie im Projektordner \bin eine Datei mit dem Namen ScrubberInterface.DLL.

Schritt 2: Erstellen Sie die Manipulationsanwendung
Unsere Anwendung ähnelt in vielen Aspekten den früheren Formularbeispielen. Anstelle einer speziellen Klasse werden aber alle Datenmanipulationsklassen eine nach der anderen verwendet.

Legen Sie eine neue Windows-Forms-Anwendung an, und nennen Sie sie ClassesOnTheFly. Platzieren Sie auf dem Formular Form1 die folgenden Steuerelemente:

Steuerelementtyp

Name

Eigenschafteneinstellungen

Button

btnLoadDataset

Text = "Load Dataset"

Button

btnScrubDataset

Text = "Scrub Dataset"

DataGrid

DataGrid1

Keine Änderungen

Fügen Sie an den Codeanfang den gleichen Code wie in dem früheren Beispiel ein:

Imports System.Configuration
Imports System.Reflection

Wir benötigen wieder eine Variable auf Modulebene, um unsere Auflistung von Konfigurationsinformationen zu speichern. Fügen Sie die folgende Zeile unter der Zeile ein, die Inherits System.Windows.Forms.Form enthält:

Dim colAvailableClasses As ArrayList

Schritt 3: Laden Sie das DataSet zum Verarbeiten in die Tabelle
Zur Vereinfachung laden wir unser DataSet aus einer XML-Datei. Legen Sie die folgende XML-Datei im Projekt ClassesOnTheFly im \bin-Verzeichnis an, und nennen Sie sie TimeCardData.xml:

<TimeCardData>
   <Employee>
      <Name>Sherlock Holmes</Name>
      <ID>123</ID>
   </Employee>
   <Employee>
      <Name>John Watson</Name>
      <ID>345</ID>
   </Employee>
   <Employee>
      <Name>Irene Adler</Name>
      <ID>567</ID>
   </Employee>
   <Employee>
      <Name>Jabez Wilson</Name>
      <ID>789</ID>
   </Employee>
</TimeCardData>

Wir benötigen einen Verweis auf das DataSet auf Modulebene. Platzieren Sie also die folgende Zeile genau unter die Zeile, die colAvailableClasses deklariert:

Dim ds As DataSet

Platzieren Sie den folgenden Code in das click-Ereignis für btnLoadDataset, um das DataSet abzurufen und die Tabelle zu laden:

ds = New DataSet()
ds.ReadXml("TimeCardData.xml")
DataGrid1.DataSource = ds.Tables(0)

Führen Sie das Programm jetzt aus, um zu testen, ob die Tabelle richtig geladen wird.

Schritt 4: Fügen Sie der Manipulationsschnittstelle einen Verweis hinzu
Als Nächstes fügen wir der DLL, die wir bereits erstellt haben, einen Verweis hinzu, der die Schnittstelle für Datenmanipulationsklassen enthält. Wählen Sie Projekt | Verweis hinzufügen. Klicken Sie auf die Schaltfläche Durchsuchen, wechseln Sie zur Datei SrcubberInterfae.DLL (oben in Schritt 1 erstellt), und klicken Sie auf Öffnen. Klicken Sie dann auf OK, um den Verweis hinzuzufügen.

Schritt 5: Speichern Sie Daten über verfügbare Formulare in der Klasse
Kopieren Sie das DynamicClass.vb-Modul, das in dem früheren Beispiel für Formulare verwendet wurde, in das ClassesOnTheFly-Projekt. Es kann ohne jede Änderung verwendet werden.

Schritt 6: Erstellen Sie eine Konfigurationsdatei, die die verfügbaren Formulare speichert
Erstellen Sie eine Konfigurationsdatei, die der ursprünglichen Datei in dem früheren Beispiel für Formulare gleicht. Sie sollte wie folgt aussehen:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <section name="availableclasses" 
               type="System.Configuration.NameValueSectionHandler" />
   </configSections>
   <availableclasses>
      <add key="Placeholder - do not load" 
           value="DLLPathnameGoesHere~NameOfTypeGoesHere"></add>
      </add>
   </availableclasses>
</configuration>

Diese Datei muss im ClassesOnTheFly-Projekt im \bin-Verzeichnis gespeichert und ClassesOnTheFly.exe.config genannt werden.

Schritt 7: Lesen Sie die Konfigurationsinformationen in eine Auflistung ein
Die Vorgehensweise ist fast die gleiche, wie sie im oben erläuterten Formularbeispiel verwendet wird, außer dass wir die Auflistung nicht an ein Kombinationsfeld binden. Kopieren Sie also die Logik aus dem Beispiel für Formulare für Form Load, und lassen Sie die letzten drei Zeilen (die zum Binden der Daten an das Kombinationsfeld dienen) weg. Fügen Sie diese Logik im ClassesOnTheFly-Projekt in Form1 in das Form Load-Ereignis ein.

Schritt 8: Fügen Sie die Logik ein, um Datenmanipulationsklassen zu laden und zu verwenden
Platzieren Sie die folgende Logik im btnScrubDataset im click-Ereignis:

Dim objScrubberClass As DynamicClass
For Each objScrubberClass In colAvailableClasses
    Dim asmAssemblyContainingForm As [Assembly] = _
        [Assembly].LoadFrom(objScrubberClass.Location)
    Dim TypeToLoad As Type = _
        asmAssemblyContainingForm.GetType(objScrubberClass.Type)
    Dim GenericInstance As Object
    GenericInstance = Activator.CreateInstance(TypeToLoad)
    Dim Scrubber As ScrubberInterface.IScrubber = _
        CType(GenericInstance, ScrubberInterface.IScrubber)
    Scrubber.Scrub(ds)
Next

Diese Logik ist der Logik zum dynamischen Laden von Formularen sehr ähnlich, so dass wir sie nicht detailliert behandeln. Die Hauptunterschiede sind:

  • Jede Klasse in der Konfigurationsdatei wird dynamisch geladen.

  • Das neu instanzierte Objekt wird in den Typ ScrubberInterface.IScrubber umgewandelt. Dadurch können wir eine Bindung an die IScrubber-Schnittstelle erstellen.

  • Die Scrub-Methode wird für jedes Objekt ausgeführt, und das DataSet wird übergeben.

Schritt 9: Kompilieren Sie die Anwendung, und führen Sie sie aus
Führen Sie die Anwendung aus, um zu prüfen, ob sie richtig kompiliert wird. Klicken Sie aber noch nicht auf die Scrub-Dataset-Schaltfläche, da die Manipulationsklasse noch nicht erstellt wurde.

Wenn die Anwendung richtig kompiliert wurde, schließen Sie das ClassesOnTheFly-Projekt in Visual Studio.

Schritt 10: Erstellen Sie die Datenmanipulationsklasse
Erstellen Sie in Visual Studio ein neues Projekt vom Typ Klassenbibliothek. Nennen Sie es FirstClass. Ersetzen Sie den automatisch eingesetzten Class1-Code durch diesen Code:

Public Class FirstClass
    Implements ScrubberInterface.IScrubber
    Public Sub Scrub(ByVal ds As DataSet) _
           Implements ScrubberInterface.IScrubber.Scrub
        Dim dr As DataRow
        dr = ds.Tables(0).NewRow
        dr.Item(0) = "Professor Moriarty"
        dr.Item(1) = "666"
        ds.Tables(0).Rows.Add(dr)
    End Sub
End Class

Diese Klasse implementiert die IScrubber-Schnittstelle, die einfach eine Methode ist. Die Methode verarbeitet ein DataSet und fügt ihm eine einzelne Zeile hinzu. Eine wirkliche Datenbereinigungsklasse könnte natürlich so viel Datenmanipulationslogik wie nötig enthalten.

Erstellen Sie das Projekt, um die Datei FirstClass.DLL zu erhalten. Kopieren Sie die DLL aus dem \bin-Projektverzeichnis in ein neues Verzeichnis namens C:\ScrubberClasses.

Schritt 11: Aktualisieren Sie die Konfigurationsdatei mit der neuen Klasse
Kehren Sie zurück zu ClassOnTheFly.exe.config. Ändern Sie den Abschnitt im <availableclasses>-Tag folgendermaßen:

<add key="First Class" 
        value="C:\ScrubberClasses\FirstClass.dll~FirstClass.FirstClass">

Speichern Sie die Konfigurationsdatei, bevor wir zum letzten Schritt kommen.

Schritt 12: Testen Sie die Funktion der neuen Datenmanipulationsklasse
Führen Sie jetzt ClassesOnTheFly.exe aus, und klicken Sie auf die Load Dataset-Schaltfläche. Die Tabelle enthält vier Zeilen. Klicken Sie auf die Scrub Dataset-Schaltfläche. In der Tabelle wird eine fünfte Zeile angezeigt, hinzugefügt durch die Datenbereinigungsklasse.

Sie könnten bei Bedarf weitere Manipulationsklassen hinzufügen, die Operationen jeder Art für das DataSet ausführen. Erstellen Sie sie einfach, und fügen Sie sie der Konfigurationsdatei hinzu. Durch einen Klick auf die Scrub Dataset-Schaltfläche werden sie automatisch verwendet.

 

Schlussfolgerung

Das wichtigste Merkmal dieser beiden Beispiele ist, dass die ursprünglichen Anwendungen (FormsOnTheFly und ClassesOnTheFly) ohne Verweise auf die Formulare und Klassen, die später dynamisch geladen wurden, erstellt und kompiliert wurden. Diese Formulare und Klassen waren tatsächlich zu diesem Zeitpunkt noch nicht einmal erstellt worden.

Als dann zu einem späteren Zeitpunkt die Formulare und Klassen erstellt wurden, wurde die Anwendung für ihre Verwendung aktualisiert: Hierfür wurde in der Konfigurationsdatei auf die Pfade und Typen der Formulare und Klassen verwiesen. Neue Formulare und Klassen können nach Bedarf erstellt und zur Laufzeit hinzugefügt werden. Wenn Sie für eine Anwendung diesen Grad an Erweiterbarkeit benötigen, bietet .NET mit Reflection und dynamischem Laden von Klassen eine ideale Lösung.