Пошаговое руководство. Создание и использование динамических объектов в Visual Basic
Динамические объекты предоставляют такие элементы, как свойства и методы, во время выполнения, а не во время компиляции. Это позволяет создавать объекты для работы со структурами, не соответствующими статическому типу или формату. Например, можно использовать динамический объект для ссылки на модель DOM HTML, которая может содержать любую комбинацию допустимых элементов и атрибутов разметки HTML. Поскольку каждый документ HTML является уникальным, элементы для конкретного документа HTML определяются во время выполнения. Наиболее распространенный способ ссылки на атрибут элемента HTML заключается в передаче имени этого атрибута в метод GetProperty
элемента. Для ссылки на атрибут id
элемента HTML <div id="Div1">
следует сначала получить ссылку на элемент <div>
, а затем использовать divElement.GetProperty("id")
. При использовании динамического объекта можно сослаться на атрибут id
в виде divElement.id
.
Динамические объекты обеспечивают удобный доступ к динамическим языкам, таким как IronPython и IronRuby. С помощью динамического объекта можно ссылаться на динамический скрипт, интерпретируемый во время выполнения.
Ссылка на динамический объект выполняется с помощью позднего связывания. Тип объекта с поздней привязкой указывается как Object
. Дополнительные сведения см. в разделе [Ранняя и поздняя привязка.
Вы можете создавать настраиваемые динамические объекты, используя классы из пространства имен System.Dynamic. Например, можно создать объект ExpandoObject и задать члены этого объекта во время выполнения. Также можно создать собственный тип, наследующий класс DynamicObject. Затем для обеспечения динамических функциональных возможностей во время выполнения можно переопределить члены класса DynamicObject.
Эта статья содержит два независимых пошаговых руководства.
Создание пользовательского объекта, который динамически предоставляет содержимое текстового файла в виде свойств объекта.
Создание проекта, использующего библиотеку
IronPython
.
Вы можете выполнить одно из них или оба, в последнем случае порядок не имеет значения.
Необходимые компоненты
- Visual Studio 2019 версии 16.9 или более поздней с установленной рабочей нагрузкой Разработка классических приложений .NET. Пакет SDK для .NET 5 устанавливается автоматически при выборе этой рабочей нагрузки.
Примечание.
Отображаемые на компьютере имена или расположения некоторых элементов пользовательского интерфейса Visual Studio могут отличаться от указанных в следующих инструкциях. Это зависит от имеющегося выпуска Visual Studio и используемых параметров. Дополнительные сведения см. в разделе Персонализация среды IDE.
- Для второго пошагового руководства установите IronPython для .NET. Перейдите на страницу загрузки для получения последней версии.
Создание пользовательского динамического объекта
В первом пошаговом руководстве определяется пользовательский динамический объект, выполняющий поиск по содержимому текстового файла. Динамическое свойство указывает искомый текст. Например, если в вызывающем коде указано dynamicFile.Sample
, динамический класс возвращает общий список строк, содержащий все строки из файла, которые начинаются со слова "Sample". При поиске не учитывается регистр. Динамический класс также поддерживает два дополнительных аргумента. Первый аргумент — это значение перечисления параметра поиска, задающее, где динамический класс должен искать соответствия: в начале строки, в конце строки или в любом месте строки. Второй аргумент задает, что динамический класс должен перед поиском отсекать начальные и конечные пробелы в каждой строке. Например, если в вызывающем коде указано dynamicFile.Sample(StringSearchOption.Contains)
, динамический класс выполняет поиск слова "Sample" в любом месте строки. Если в вызывающем коде указано dynamicFile.Sample(StringSearchOption.StartsWith, false)
, динамический класс выполняет поиск слова "Sample" в начале каждой строки и не удаляет начальные и конечные пробелы в строках. По умолчанию динамический класс выполняет поиск соответствия в начале каждой строки, предварительно удаляя начальные и конечные пробелы.
Создание пользовательского динамического класса
Запустите Visual Studio.
Выберите Создать новый проект.
В диалоговом окне "Создание проекта" выберите Visual Basic, выберите консольное приложение и нажмите кнопку "Далее".
В диалоговом окне Настройка нового проекта введите значение
DynamicSample
для параметра Имя проекта и нажмите кнопку Далее.В диалоговом окне Дополнительные сведения выберите значение .NET 5.0 (текущая) для параметра Целевая платформа, а затем нажмите кнопку Создать.
Создается новый проект.
В обозревателе решений щелкните проект DynamicSample правой кнопкой мыши и выберите Добавить>Класс. В поле Имя введите
ReadOnlyFile
, а затем нажмите кнопку Добавить.Будет добавлен новый файл, содержащий класс ReadOnlyFile.
В верхней части файла ReadOnlyFile.cs илиReadOnlyFile.vb добавьте следующий код для импорта пространств имен System.IO и System.Dynamic.
Imports System.IO Imports System.Dynamic
Пользовательский динамический объект использует перечисление для определения условия поиска. Перед оператором класса добавьте следующее определение перечисления.
Public Enum StringSearchOption StartsWith Contains EndsWith End Enum
Обновите оператор класса, чтобы он наследовал класс
DynamicObject
, как показано в следующем примере кода.Public Class ReadOnlyFile Inherits DynamicObject
Добавьте в класс
ReadOnlyFile
следующий код, чтобы задать закрытое поле для пути к файлу и конструктор для классаReadOnlyFile
.' 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
Добавьте приведенный ниже метод
GetPropertyValue
в классReadOnlyFile
. МетодGetPropertyValue
принимает в качестве входных данных условие поиска и возвращает строки текстового файла, соответствующие этому условию. Динамический метод, предоставленный классомReadOnlyFile
, вызывает методGetPropertyValue
для извлечения соответствующих результатов.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
После метода
GetPropertyValue
добавьте следующий код, чтобы переопределить метод TryGetMember класса DynamicObject. Метод TryGetMember вызывается при запросе члена динамического класса без указания аргументов. Аргументbinder
содержит сведения об элементе, на который дается ссылка, а аргументresult
ссылается на результат, возвращенный для указанного элемента. Метод TryGetMember возвращает логическое значениеtrue
, если запрошенный элемент существует. В противном случае возвращаетсяfalse
.' 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
После метода
TryGetMember
добавьте следующий код, чтобы переопределить метод TryInvokeMember класса DynamicObject. Метод TryInvokeMember вызывается при запросе члена динамического класса с аргументами. Аргументbinder
содержит сведения об элементе, на который дается ссылка, а аргументresult
ссылается на результат, возвращенный для указанного элемента. Аргументargs
содержит массив аргументов, передаваемых в элемент. Метод TryInvokeMember возвращает логическое значениеtrue
, если запрошенный элемент существует. В противном случае возвращаетсяfalse
.Пользовательская версия метода
TryInvokeMember
ожидает, что первый аргумент будет значением из перечисленияStringSearchOption
, заданного на предыдущем шаге. МетодTryInvokeMember
ожидает, что второй аргумент будет логическим значением. Если один или оба элемента имеют допустимые значения, они передаются в методGetPropertyValue
для получения результатов.' 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
Сохранить и закрыть файл.
Создание примера текстового файла
В обозревателе решений щелкните проект DynamicSample правой кнопкой мыши и выберите Добавить>Новый элемент. На панели Установленные шаблоны выберите Общие, а затем шаблон Текстовый файл. В поле Имя оставьте имя по умолчанию TextFile1.txt и нажмите кнопку Добавить. В проект добавится новый текстовый файл.
Скопируйте в файл 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
Сохранить и закрыть файл.
Создание примера приложения, в котором применяется пользовательский динамический объект
В Обозреватель решений дважды щелкните файл Program.vb.
Добавьте следующий код в процедуру
Main
, чтобы создать экземпляр классаReadOnlyFile
для файла TextFile1.txt. В этом коде используется позднее связывание для вызова динамических элементов и извлечения строк текста, которые содержат строку "Customer".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
Сохраните файл и нажмите клавиши CTRL+F5 для сборки и запуска приложения.
Вызов библиотеки динамического языка
В следующем пошаговом руководстве создается проект, который осуществляет доступ к библиотеке, написанной на динамическом языке IronPython.
Создание пользовательского динамического класса
В Visual Studio выберите Файл>Создать>Проект.
В диалоговом окне "Создание проекта" выберите Visual Basic, выберите консольное приложение и нажмите кнопку "Далее".
В диалоговом окне Настройка нового проекта введите значение
DynamicIronPythonSample
для параметра Имя проекта и нажмите кнопку Далее.В диалоговом окне Дополнительные сведения выберите значение .NET 5.0 (текущая) для параметра Целевая платформа, а затем нажмите кнопку Создать.
Создается новый проект.
Установите пакет NuGet IronPython.
Измените файл Program.vb .
В верхней части файла добавьте следующий код для импорта пространств имен
Microsoft.Scripting.Hosting
иIronPython.Hosting
из библиотек IronPython и пространства именSystem.Linq
.Imports Microsoft.Scripting.Hosting Imports IronPython.Hosting Imports System.Linq
В методе Main добавьте следующий код, чтобы создать объект
Microsoft.Scripting.Hosting.ScriptRuntime
, в котором будут размещены библиотеки IronPython. ОбъектScriptRuntime
загружает модуль библиотеки IronPython 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.")
После указания в коде необходимости загрузки модуля random.py добавьте следующий код, чтобы создать массив целых чисел. Массив передается методу
shuffle
модуля random.py, который произвольно сортирует значения в массиве.' 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
Сохраните файл и нажмите клавиши CTRL+F5 для сборки и запуска приложения.