Exemplarische Vorgehensweise: Erstellen und Verwenden von dynamischen Objekten in Visual Basic
Dynamische Objekte machen Member wie etwa Eigenschaften und Methoden zur Laufzeit anstatt zur Kompilierzeit verfügbar. Dadurch können Sie Objekte erstellen, mit denen Sie mit Strukturen arbeiten können, die keinem statischen Typ oder Format entsprechen. Sie können z.B. ein dynamisches Objekt verwenden, um auf das HTML-DOM (Document Object Model) zu verweisen, das eine Kombination aus gültigen HTML-Markupelementen und Attributen enthalten kann. Da jedes HTML-Dokument eindeutig ist, werden die Elemente für ein bestimmtes HTML-Dokument zur Laufzeit bestimmt. Eine gängige Methode zum Verweisen eines Attributes auf ein HTML-Element ist, den Namen des Attributs an die GetProperty
-Methode des Elements weiterzugeben. Rufen Sie zum Verweisen des id
-Attributs auf das HTML-Element <div id="Div1">
zuerst einen Verweis auf das <div>
-Element ab, und verwenden Sie anschließend divElement.GetProperty("id")
. Wenn Sie ein dynamisches Objekt verwenden, können Sie auf das id
-Attribut als divElement.id
verweisen.
Dynamische Objekte bieten außerdem einfachen Zugriff auf dynamische Sprachen wie IronPython und IronRuby. Sie können ein dynamisches Objekt verwenden, um sich auf ein dynamisches Skript zu beziehen, das zur Laufzeit ausgeführt wird.
Sie verweisen auf ein dynamisches Objekt mithilfe der späten Bindung. Geben Sie den Typ eines spät gebundenen Objekts als Object
an. Weitere Informationen finden Sie unter Frühes und spätes Binden.
Sie können benutzerdefinierte dynamische Objekte erstellen, indem Sie die Klassen im System.Dynamic-Namespace verwenden. Sie können z.B. ein ExpandoObject erstellen und die Member dieses Objekts zur Laufzeit angeben. Sie können auch einen eigenen Typ erstellen, der die DynamicObject-Klasse erbt. Sie können die Member dieser DynamicObject-Klasse anschließend außer Kraft setzen, um dynamische Funktionen zur Laufzeit bereitzustellen.
Dieser Artikel enthält zwei voneinander unabhängige exemplarische Vorgehensweisen:
Erstellen Sie ein benutzerdefiniertes Objekt, das die Inhalte einer Textdatei als Eigenschaften eines Objekts weitergibt.
Erstellen Sie ein Objekt, das die
IronPython
-Bibliothek verwendet.
Sie können wählen, ob Sie eine Vorgehensweise oder beide absolvieren möchten (dabei spielt die Reihenfolge keine Rolle).
Voraussetzungen
- Visual Studio 2019 Version 16.9 oder höher mit installierter Workload .NET Desktop-Entwicklung. Wenn Sie diese Workload auswählen, wird .NET SDK 5 automatisch installiert.
Hinweis
Auf Ihrem Computer werden möglicherweise andere Namen oder Speicherorte für die Benutzeroberflächenelemente von Visual Studio angezeigt als die in den folgenden Anweisungen aufgeführten. Diese Elemente sind von der jeweiligen Visual Studio-Version und den verwendeten Einstellungen abhängig. Weitere Informationen finden Sie unter Personalisieren der IDE.
- Wenn Sie die zweite exemplarische Vorgehensweise absolvieren möchten, installieren Sie IronPython für .NET. Wechseln Sie zur Downloadseite, um die neueste Version zu erhalten.
Erstellen eines benutzerdefinierten dynamischen Objekts
In der ersten exemplarischen Vorgehensweise wird ein benutzerdefiniertes dynamisches Objekt definiert, mit dem der Inhalt einer Textdatei durchsucht wird. Mit einer dynamischen Eigenschaft wird der Text angegeben, nach dem gesucht werden soll. Wenn aufrufender Code z.B. dynamicFile.Sample
angibt, gibt die dynamische Klasse eine generische Liste von Zeichenfolgen zurück, die alle Zeilen aus der Datei enthält, die mit „Sample“ anfangen. Die Groß- und Kleinschreibung wird bei der Suche nicht berücksichtigt. Die dynamische Klasse unterstützt auch zwei optionale Argumente. Das erste Argument ist ein Enumerationswert einer Suchoption, der angibt, dass die dynamische Klasse am Beginn, am Ende oder an einer beliebigen Stelle der Zeile nach Übereinstimmungen suchen soll. Das zweite Argument gibt an, dass die dynamische Klasse führende und nachfolgende Leerzeichen vor dem Suchvorgang aus jeder Zeile entfernen soll. Wenn aufrufender Code z.B. dynamicFile.Sample(StringSearchOption.Contains)
angibt, sucht die dynamische Klasse an einer beliebigen Stelle in der Zeile nach „Sample“. Wenn der aufrufende Code dynamicFile.Sample(StringSearchOption.StartsWith, false)
angibt, sucht die dynamische Klasse am Beginn jeder Zeile nach „Sample“ und entfernt keine führenden oder nachfolgenden Leerzeichen. Standardmäßig sucht die dynamische Klasse nach Übereinstimmungen am Beginn jeder Zeile und entfernt führende oder nachfolgende Leerzeichen.
So erstellen Sie eine benutzerdefinierte dynamische Klasse
Starten Sie Visual Studio.
Wählen Sie Neues Projekt erstellen aus.
Wählen Sie im Dialogfeld Neues Projekt erstellen die Option „Visual Basic“ aus, wählen Sie Konsolenanwendung und anschließend Weiter.
Geben Sie im Dialogfeld Neues Projekt konfigurieren für Projektname den Text
DynamicSample
ein, und klicken Sie dann auf Weiter.Wählen Sie im Dialogfeld Zusätzliche Informationen für Zielframework die Option .NET 5.0 (aktuell) aus, und klicken Sie dann auf Erstellen.
Das neue Projekt wird erstellt.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt „DynamicSample“, und klicken Sie anschließend auf Hinzufügen>Klasse. Geben Sie im Feld Name den Text
ReadOnlyFile
ein, und klicken Sie dann auf Hinzufügen.Eine neue Datei wird hinzugefügt, die die Klasse „ReadOnlyFile“ enthält.
Fügen Sie am Anfang der Datei ReadOnlyFile.cs oder ReadOnlyFile.vb den folgenden Code hinzu, um die Namespaces System.IO und System.Dynamic zu importieren.
Imports System.IO Imports System.Dynamic
Das benutzerdefinierte dynamische Objekt verwendet einen Enumerationswert, um die Suchkriterien zu bestimmen. Fügen Sie vor der class-Anweisung die folgende Enumerationsdefinition ein.
Public Enum StringSearchOption StartsWith Contains EndsWith End Enum
Aktualisieren Sie die class-Anweisung wie im folgenden Beispiel, um die
DynamicObject
-Klasse zu erben.Public Class ReadOnlyFile Inherits DynamicObject
Fügen Sie den folgenden Code zur
ReadOnlyFile
-Klasse hinzu, um ein privates Feld für den Dateipfad und einen Konstruktor für dieReadOnlyFile
-Klasse zu definieren.' Store the path to the file and the initial line count value. Private p_filePath As String ' Public constructor. Verify that file exists and store the path in ' the private variable. Public Sub New(ByVal filePath As String) If Not File.Exists(filePath) Then Throw New Exception("File path does not exist.") End If p_filePath = filePath End Sub
Fügen Sie die folgende
GetPropertyValue
-Methode zu derReadOnlyFile
-Klasse hinzu. DieGetPropertyValue
-Methode akzeptiert Suchkriterien als Eingabe und gibt die Zeilen aus einer Textdatei zurück, die den Suchkriterien entsprechen. Die von derReadOnlyFile
-Klasse bereitgestellten Methoden rufen dieGetPropertyValue
-Methode auf, um ihre entsprechenden Ergebnisse abzurufen.Public Function GetPropertyValue(ByVal propertyName As String, Optional ByVal StringSearchOption As StringSearchOption = StringSearchOption.StartsWith, Optional ByVal trimSpaces As Boolean = True) As List(Of String) Dim sr As StreamReader = Nothing Dim results As New List(Of String) Dim line = "" Dim testLine = "" Try sr = New StreamReader(p_filePath) While Not sr.EndOfStream line = sr.ReadLine() ' Perform a case-insensitive search by using the specified search options. testLine = UCase(line) If trimSpaces Then testLine = Trim(testLine) Select Case StringSearchOption Case StringSearchOption.StartsWith If testLine.StartsWith(UCase(propertyName)) Then results.Add(line) Case StringSearchOption.Contains If testLine.Contains(UCase(propertyName)) Then results.Add(line) Case StringSearchOption.EndsWith If testLine.EndsWith(UCase(propertyName)) Then results.Add(line) End Select End While Catch ' Trap any exception that occurs in reading the file and return Nothing. results = Nothing Finally If sr IsNot Nothing Then sr.Close() End Try Return results End Function
Fügen Sie nach der
GetPropertyValue
-Methode den folgenden Code hinzu, um die TryGetMember-Methode der DynamicObject-Klasse zu überschreiben. Die Methode TryGetMember wird aufgerufen, wenn ein Member einer dynamischen Klasse angefordert wird und keine Argumente angegeben werden. Das Argumentbinder
enthält Informationen über den Member, auf den verwiesen wurde. Das Argumentresult
verweist auf das Ergebnis, das für den angegebenen Member zurückgegeben wird. Die Methode TryGetMember gibt einen booleschen Wert zurück, dertrue
zurückgibt, wenn der angeforderte Member vorhanden ist; andernfalls wirdfalse
zurückgegeben.' Implement the TryGetMember method of the DynamicObject class for dynamic member calls. Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean result = GetPropertyValue(binder.Name) Return If(result Is Nothing, False, True) End Function
Fügen Sie nach der
TryGetMember
-Methode den folgenden Code hinzu, um die TryInvokeMember-Methode der DynamicObject-Klasse zu überschreiben. Die TryInvokeMember-Methode wird aufgerufen, wenn ein Mitglied einer dynamischen Klasse mit Argumenten angefordert wird. Das Argumentbinder
enthält Informationen über den Member, auf den verwiesen wurde. Das Argumentresult
verweist auf das Ergebnis, das für den angegebenen Member zurückgegeben wird. Das Argumentargs
enthält ein Array von Argumenten, die an den Member weitergegeben werden. Die Methode TryInvokeMember gibt einen booleschen Wert zurück, dertrue
zurückgibt, wenn der angeforderte Member vorhanden ist; andernfalls wirdfalse
zurückgegeben.Die benutzerdefinierte Version der Methode
TryInvokeMember
erwartet, dass es sich beim ersten Argument um einen Wert derStringSearchOption
-Enumeration handelt, die Sie in einem vorherigen Schritt definiert haben. Die MethodeTryInvokeMember
erwartet, dass es sich beim zweiten Argument um einen booleschen Wert handelt. Wenn es sich bei einem oder beiden Argumenten um gültige Werte handelt, werden sie an die MethodeGetPropertyValue
zum Abrufen der Werte weitergegeben.' Implement the TryInvokeMember method of the DynamicObject class for ' dynamic member calls that have arguments. Public Overrides Function TryInvokeMember(ByVal binder As InvokeMemberBinder, ByVal args() As Object, ByRef result As Object) As Boolean Dim StringSearchOption As StringSearchOption = StringSearchOption.StartsWith Dim trimSpaces = True Try If args.Length > 0 Then StringSearchOption = CType(args(0), StringSearchOption) Catch Throw New ArgumentException("StringSearchOption argument must be a StringSearchOption enum value.") End Try Try If args.Length > 1 Then trimSpaces = CType(args(1), Boolean) Catch Throw New ArgumentException("trimSpaces argument must be a Boolean value.") End Try result = GetPropertyValue(binder.Name, StringSearchOption, trimSpaces) Return If(result Is Nothing, False, True) End Function
Speichern und schließen Sie die Datei.
So erstellen Sie eine Beispieltextdatei
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt „DynamicSample“, und klicken Sie anschließend auf Hinzufügen>Neues Element. Wählen Sie im Bereich Installierte VorlagenAllgemein aus, und wählen Sie anschließend die Vorlage Textdatei aus. Übernehmen Sie im Feld Name den Standardnamen der Datei TextFile1.txt, und klicken Sie dann auf Hinzufügen. Eine neue Textdatei wird zum Projekt hinzugefügt.
Kopieren Sie den folgenden Text in die Datei TextFile1.txt.
List of customers and suppliers Supplier: Lucerne Publishing (https://www.lucernepublishing.com/) Customer: Preston, Chris Customer: Hines, Patrick Customer: Cameron, Maria Supplier: Graphic Design Institute (https://www.graphicdesigninstitute.com/) Supplier: Fabrikam, Inc. (https://www.fabrikam.com/) Customer: Seubert, Roxanne Supplier: Proseware, Inc. (http://www.proseware.com/) Customer: Adolphi, Stephan Customer: Koch, Paul
Speichern und schließen Sie die Datei.
So erstellen Sie eine Beispielanwendung, die das benutzerdefinierte dynamische Objekt enthält
Doppelklicken Sie in Projektmappen-Explorer auf die Datei Program.vb.
Fügen Sie der
Main
-Prozedur den folgenden Code hinzu, um eine Instanz der KlasseReadOnlyFile
für die Datei TextFile1.txt zu erstellen. Der Code verwendet spätes Binden, um dynamische Member aufzurufen und die Textzeilen abzurufen, die die Zeichenfolge „Customer“ (Kunde) enthalten.Dim rFile As Object = New ReadOnlyFile("..\..\..\TextFile1.txt") For Each line In rFile.Customer Console.WriteLine(line) Next Console.WriteLine("----------------------------") For Each line In rFile.Customer(StringSearchOption.Contains, True) Console.WriteLine(line) Next
Speichern Sie die Datei, und drücken Sie STRG+F5, um die Anwendung zu erstellen und auszuführen.
Aufrufen einer Bibliothek in einer dynamischen Sprache
In der folgenden exemplarischen Vorgehensweise wird ein Projekt erstellt, das auf eine Bibliothek zugreift, die in der dynamischen Sprache IronPython geschrieben ist.
So erstellen Sie eine benutzerdefinierte dynamische Klasse
Klicken Sie in Visual Studio auf Datei>Neu>Projekt.
Wählen Sie im Dialogfeld Neues Projekt erstellen die Option „Visual Basic“ aus, wählen Sie Konsolenanwendung und anschließend Weiter.
Geben Sie im Dialogfeld Neues Projekt konfigurieren für Projektname den Text
DynamicIronPythonSample
ein, und klicken Sie dann auf Weiter.Wählen Sie im Dialogfeld Zusätzliche Informationen für Zielframework die Option .NET 5.0 (aktuell) aus, und klicken Sie dann auf Erstellen.
Das neue Projekt wird erstellt.
Installieren Sie das NuGet-Paket IronPython.
Bearbeiten Sie die Datei Program.vb.
Fügen Sie am Anfang der Datei den folgenden Code hinzu, um die Namespaces
Microsoft.Scripting.Hosting
undIronPython.Hosting
aus den IronPython-Bibliotheken zu importieren sowie den NamespaceSystem.Linq
.Imports Microsoft.Scripting.Hosting Imports IronPython.Hosting Imports System.Linq
Fügen Sie in der Main-Methode den folgenden Code zum Erstellen eines neuen
Microsoft.Scripting.Hosting.ScriptRuntime
-Objekts zum Hosten der IronPython-Bibliotheken hinzu. DasScriptRuntime
-Objekt lädt das IronPython-Bibliotheksmodul „random.py“.' Set the current directory to the IronPython libraries. System.IO.Directory.SetCurrentDirectory( Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) & "\IronPython 2.7\Lib") ' Create an instance of the random.py IronPython library. Console.WriteLine("Loading random.py") Dim py = Python.CreateRuntime() Dim random As Object = py.UseFile("random.py") Console.WriteLine("random.py loaded.")
Fügen Sie nach dem Code zum Laden des Moduls „random.py“ den folgenden Code zum Erstellen eines Arrays von ganzen Zahlen hinzu. Das Array wird an die
shuffle
-Methode des Moduls „random.py“ übergeben, das die Werte im Array per Zufall sortiert.' Initialize an enumerable set of integers. Dim items = Enumerable.Range(1, 7).ToArray() ' Randomly shuffle the array of integers by using IronPython. For i = 0 To 4 random.shuffle(items) For Each item In items Console.WriteLine(item) Next Console.WriteLine("-------------------") Next
Speichern Sie die Datei, und drücken Sie STRG+F5, um die Anwendung zu erstellen und auszuführen.