Compartilhar via


Passo a passo: criar e usar objetos dinâmicos no Visual Basic

Os objetos dinâmicos expõem membros como propriedades e métodos em tempo de execução, em vez de em tempo de compilação. Isso permite que você crie objetos para trabalhar com estruturas que não correspondem a um formato ou tipo estático. Por exemplo, você pode usar um objeto dinâmico para fazer referência ao DOM (Modelo de Objeto do Documento) HTML, que pode conter qualquer combinação de atributos e elementos de marcação HTML válidos. Como cada documento HTML é único, os membros de um determinado documento HTML são determinados em tempo de execução. Um método comum para fazer referência a um atributo de um elemento HTML é passar o nome do atributo para o método GetProperty do elemento. Para fazer referência ao atributo id do elemento HTML <div id="Div1">, primeiro você obtém uma referência ao elemento <div> e, depois, usa divElement.GetProperty("id"). Se usar um objeto dinâmico, você poderá fazer referência ao atributo id como divElement.id.

Objetos dinâmicos também fornecem acesso conveniente a linguagens dinâmicas, como IronPython e IronRuby. É possível usar um objeto dinâmico para fazer referência a um script dinâmico que é interpretado em tempo de execução.

Você faz referência a um objeto dinâmico usando a associação tardia. Especifique o tipo de um objeto com associação tardia como Object. Para obter mais informações, confira Associação Antecipada e Tardia.

Você pode criar objetos dinâmicos personalizados usando classes no namespace System.Dynamic. Por exemplo, é possível criar um ExpandoObject e especificar os membros desse objeto em tempo de execução. Você também pode criar seu próprio tipo que herda da classe DynamicObject. Em seguida, você pode substituir os membros da classe DynamicObject para fornecer funcionalidade dinâmica de tempo de execução.

Este artigo contém dois passo a passo independentes:

  • Criar um objeto personalizado que expõe dinamicamente o conteúdo de um arquivo de texto como propriedades de um objeto.

  • Criar um projeto que usa uma biblioteca IronPython.

Você pode seguir apenas um deles ou ambos, e, caso escolha seguir os dois, a ordem não importará.

Pré-requisitos

Observação

Seu computador pode mostrar diferentes nomes ou locais para alguns dos elementos de interface do usuário do Visual Studio nas instruções a seguir. A edição do Visual Studio que você possui e as configurações que você usa determinam esses elementos. Para obter mais informações, consulte Personalizando o IDE.

Criar um objeto dinâmico personalizado

O primeiro passo a passo define um objeto dinâmico personalizado que pesquisa o conteúdo de um arquivo de texto. Uma propriedade dinâmica especifica o texto a ser pesquisado. Por exemplo, se o código de chamada especificar dynamicFile.Sample, a classe dinâmica retornará uma lista genérica de cadeias de caracteres que contém todas as linhas do arquivo que começam com "Sample". A pesquisa diferencia maiúsculas de minúsculas. A classe dinâmica também dá suporte a dois argumentos opcionais. O primeiro argumento é um valor de enum de opção de pesquisa que especifica que a classe dinâmica deve pesquisar por correspondências no início da linha, no final da linha ou em qualquer lugar da linha. O segundo argumento especifica que a classe dinâmica deve cortar espaços iniciais e finais de cada linha antes de pesquisar. Por exemplo, se o código de chamada especificar dynamicFile.Sample(StringSearchOption.Contains), a classe dinâmica pesquisará por "Sample" em qualquer lugar de uma linha. Se o código de chamada especificar dynamicFile.Sample(StringSearchOption.StartsWith, false), a classe dinâmica pesquisará por "Sample" no início de cada linha e não removerá espaços à direita e à esquerda. O comportamento padrão da classe dinâmica é pesquisar por uma correspondência no início de cada linha e remover espaços à direita e à esquerda.

Para criar uma classe dinâmica personalizada

  1. Inicie o Visual Studio.

  2. Selecione Criar um novo projeto.

  3. Na caixa de diálogo Criar um novo projeto, selecione Visual Basic, selecione Aplicativo de Console e, em seguida, Avançar.

  4. Na caixa de diálogo Configurar novo projeto, digite DynamicSample como Nome do projeto e selecione em Avançar.

  5. Na caixa de diálogo Informações adicionais, selecione .NET 5.0 (atual) como Estrutura de destino e, em seguida, selecione Criar.

    Quando um novo projeto é criado.

  6. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto DynamicSample e selecione Adicionar>Classe. Na caixa Nome, digite ReadOnlyFile e selecione Adicionar.

    É adicionado um novo arquivo que contém a classe ReadOnlyFile.

  7. Na parte superior do arquivo ReadOnlyFile.cs ou ReadOnlyFile.vb, adicione o código a seguir para importar os namespaces System.IO e System.Dynamic.

    Imports System.IO
    Imports System.Dynamic
    
  8. O objeto dinâmico personalizado usa um enum para determinar os critérios de pesquisa. Antes da instrução de classe, adicione a seguinte definição de enum.

    Public Enum StringSearchOption
        StartsWith
        Contains
        EndsWith
    End Enum
    
  9. Atualize a instrução de classe para herdar a classe DynamicObject, conforme mostrado no exemplo de código a seguir.

    Public Class ReadOnlyFile
        Inherits DynamicObject
    
  10. Adicione o código a seguir para a classe ReadOnlyFile para definir um campo particular para o caminho do arquivo e um construtor para a classe 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
    
  11. Adicione o seguinte método GetPropertyValue à classe ReadOnlyFile. O método GetPropertyValue usa, como entrada, critérios de pesquisa e retorna as linhas de um arquivo de texto que correspondem a esse critério de pesquisa. Os métodos dinâmicos fornecidos pela classe ReadOnlyFile chamam o método GetPropertyValue para recuperar seus respectivos resultados.

    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
    
  12. Após o método GetPropertyValue, adicione o seguinte código para substituir o método TryGetMember da classe DynamicObject. O método TryGetMember é chamado quando um membro de uma classe dinâmica é solicitado e nenhum argumento é especificado. O argumento binder contém informações sobre o membro referenciado e o argumento result faz referência ao resultado retornado para o membro especificado. O método TryGetMember retorna um valor booliano que retorna true se o membro solicitado existe; caso contrário, ele retorna 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
    
  13. Após o método TryGetMember, adicione o seguinte código para substituir o método TryInvokeMember da classe DynamicObject. O método TryInvokeMember é chamado quando um membro de uma classe dinâmica é solicitado com argumentos. O argumento binder contém informações sobre o membro referenciado e o argumento result faz referência ao resultado retornado para o membro especificado. O argumento args contém uma matriz de argumentos que são passados ao membro. O método TryInvokeMember retorna um valor booliano que retorna true se o membro solicitado existe; caso contrário, ele retorna false.

    A versão personalizada do método TryInvokeMember espera que o primeiro argumento seja um valor do enum StringSearchOption que você definiu na etapa anterior. O método TryInvokeMember espera que o segundo argumento seja um valor booliano. Se um ou os dois argumentos forem valores válidos, eles serão passados para o método GetPropertyValue para recuperar os resultados.

    ' 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
    
  14. Salve e feche o arquivo.

Para criar um arquivo de texto de exemplo

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto DynamicSample e selecione Adicionar>Novo item. No painel Modelos Instalados, selecione Geral e, então, selecione o modelo Arquivo de Texto. Deixe o nome padrão de TextFile1.txt na caixa Nome e, em seguida, clique em Adicionar. Um novo arquivo de texto é adicionado ao projeto.

  2. Copie o seguinte texto para o arquivo 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
    
  3. Salve e feche o arquivo.

Para criar um aplicativo de exemplo que usa o objeto dinâmico personalizado

  1. Em Gerenciador de Soluções, clique duas vezes no arquivo Program.vb.

  2. Adicione o código a seguir ao procedimento Main para criar uma instância da classe ReadOnlyFile para o arquivo TextFile1.txt. O código usa associação tardia para chamar membros dinâmicos e recuperar linhas de texto que contêm a cadeia de caracteres "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
    
  3. Salve o arquivo e pressione Ctrl+F5 para compilar e executar o aplicativo.

Chamar uma biblioteca de linguagem dinâmica

O próximo passo a passo cria um projeto que acessa uma biblioteca escrita na linguagem dinâmica IronPython.

Para criar uma classe dinâmica personalizada

  1. No Visual Studio, selecione Arquivo>Novo>Projeto.

  2. Na caixa de diálogo Criar um novo projeto, selecione Visual Basic, selecione Aplicativo de Console e, em seguida, Avançar.

  3. Na caixa de diálogo Configurar novo projeto, digite DynamicIronPythonSample como Nome do projeto e selecione em Avançar.

  4. Na caixa de diálogo Informações adicionais, selecione .NET 5.0 (atual) como Estrutura de destino e, em seguida, selecione Criar.

    Quando um novo projeto é criado.

  5. Instale o pacote NuGet do IronPython.

  6. Edite o arquivo Program.vb.

  7. Na parte superior do arquivo, adicione o código a seguir para importar os namespaces Microsoft.Scripting.Hosting e IronPython.Hosting das bibliotecas do IronPython e o namespace System.Linq.

    Imports Microsoft.Scripting.Hosting
    Imports IronPython.Hosting
    Imports System.Linq
    
  8. No método Main, adicione o código a seguir para criar um novo objeto Microsoft.Scripting.Hosting.ScriptRuntime para hospedar as bibliotecas do IronPython. O objeto ScriptRuntime carrega o módulo random.py da biblioteca do IronPython.

    ' 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.")
    
  9. Após o código carregar o módulo random.py, adicione o seguinte código para criar uma matriz de inteiros. A matriz é passada para o método shuffle do módulo random.py, que classifica aleatoriamente os valores na matriz.

    ' 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
    
  10. Salve o arquivo e pressione Ctrl+F5 para compilar e executar o aplicativo.

Confira também