Partilhar via


Passo a passo: Criando e usando objetos dinâmicos (C# e Visual Basic)

Os objetos dinâmicos membros expostos 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 um tipo ou um formato estático.Por exemplo, você pode usar um objeto dinâmico para fazer referência ao modelo de objeto (DOM) do documento HTML, que pode conter qualquer combinação de elementos e atributos válidos de marcação HTML.Porque cada documento HTML é exclusivo, os membros para um documento HTML de detalhes 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 de GetProperty do elemento.Para fazer referência ao atributo de id do elemento HTML <div id="Div1">, você primeiro obtenha uma referência ao elemento de <div> e em seguida, usa divElement.GetProperty("id").Se você usar um objeto dinâmico, você pode referenciar o atributo de id como divElement.id.

Os objetos dinâmicos também fornecem acesso conveniente às linguagens dinâmicos como IronPython e IronRuby.Você pode usar um objeto dinâmico para se referir a um script dinâmico que é interpretado em tempo de execução.

Você referencia um objeto dinâmico usando associação tardia.Em C#, você especifica o tipo de um objeto de associação tardia como dynamic.Em Visual Basic, você especifica o tipo de um objeto de associação tardia como Object.Para obter mais informações, consulte dinâmico (referência de C#) e (Visual Basic) de vinculação antecipada e atrasada.

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

Em essa explicação passo a passo você executará as seguintes tarefas:

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

  • Crie um projeto que usa uma biblioteca de IronPython .

Pré-requisitos

Você precisa IronPython 2.6.1 para .NET 4,0 para concluir esta explicação passo a passo.você pode baixar IronPython 2.6.1 para .NET 4,0 de CodePlex.

ObservaçãoObservação

Seu computador pode mostrar nomes ou locais diferentes para alguns dos elementos da 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 Configurações de Visual Studio.

criando um objeto dinâmico personalizado

O primeiro projeto que você criou em essa explicação passo a passo define um objeto dinâmico personalizado que procura o conteúdo de um arquivo de texto.O texto a procurar pelo especificado pelo nome de uma propriedade dinâmica.Por exemplo, se chamar o código especifica dynamicFile.Sample, a classe dinâmica retorna uma lista genérica de cadeias de caracteres que contém todas as linhas do arquivo que começam com “exemplo”.A pesquisa não difere maiúsculas de minúsculas.A classe dinâmica também suporta dois argumentos opcionais.O primeiro argumento é um valor enum de opção de pesquisa que especifica que a classe dinâmica deve procurar por correspondências no início da linha, ao final da linha, ou em qualquer lugar na linha.O segundo argumento especifica que a classe dinâmica deve ser preparada espaćamento e o espaço à esquerda de cada linha antes de procurar.Por exemplo, se chamar o código especifica dynamicFile.Sample(StringSearchOption.Contains), pesquisas dinâmicos da classe para “exemplo” em qualquer lugar em uma linha.Se chamar o código especifica dynamicFile.Sample(StringSearchOption.StartsWith, false), a classe dinâmica procura por exemplo “” no início de cada linha, e não remove ao primeiro e o espaço à direita.O comportamento padrão da classe dinâmica é procurar por um correspondente no início de cada linha e remover ao primeiro e o espaço à direita.

Para criar uma classe dinâmica personalizado

  1. Inicie o Visual Studio

  2. No menu File, aponte para New e clique Project.

  3. Em a caixa de diálogo de Novo Projeto , no painel de Tipos de projeto , certifique-se que está selecionado Janelas .Aplicativo de Console Selecione no painel de Modelos .Em a caixa de Nome , o tipo DynamicSample, e clique em OK.o novo projeto é criado.

  4. Clique com o botão direito do mouse no projeto e o ponto de DynamicSample a Adicionar, clique em Classe.Em a caixa de Nome , o tipo ReadOnlyFile, e clique em OK.Um novo arquivo é adicionado que contém a classe de ReadOnlyFile.

  5. Em a parte superior do arquivo de ReadOnlyFile.cs ou de ReadOnlyFile.vb, adicione o seguinte código para importar System.IO e namespaces de System.Dynamic .

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

    Public Enum StringSearchOption
        StartsWith
        Contains
        EndsWith
    End Enum
    
    public enum StringSearchOption
    {
        StartsWith,
        Contains,
        EndsWith
    }
    
  7. Atualizar a declaração de classe para herdar a classe de DynamicObject , conforme mostrado no exemplo de código a seguir.

    Public Class ReadOnlyFile
        Inherits DynamicObject
    
    class ReadOnlyFile : DynamicObject
    
  8. Adicione o seguinte código à classe de ReadOnlyFile para definir um campo particular para o caminho do arquivo e um construtor para a classe de 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
    
    // Store the path to the file and the initial line count value.
    private string p_filePath;
    
    // Public constructor. Verify that file exists and store the path in 
    // the private variable.
    public ReadOnlyFile(string filePath)
    {
        if (!File.Exists(filePath))
        {
            throw new Exception("File path does not exist.");
        }
    
        p_filePath = filePath;
    }
    
  9. Adicione o seguinte método de GetPropertyValue a classe de ReadOnlyFile .O método de GetPropertyValue aceita, como entrada, os critérios de pesquisa e retorna as linhas de um arquivo de texto que que correspondem critérios de pesquisa.Métodos dinâmicos fornecido pela classe de ReadOnlyFile chama o método de 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
    
    public List<string> GetPropertyValue(string propertyName,
                                         StringSearchOption StringSearchOption = StringSearchOption.StartsWith,
                                         bool trimSpaces = true) 
    {
        StreamReader sr = null;
        List<string> results = new List<string>();
        string line = "";
        string testLine = "";
    
        try
        {
            sr = new StreamReader(p_filePath);
    
            while (!sr.EndOfStream)
            {
                line = sr.ReadLine();
    
                // Perform a case-insensitive search by using the specified search options.
                testLine = line.ToUpper();
                if (trimSpaces) { testLine = testLine.Trim(); }
    
                switch (StringSearchOption)
                {
                    case StringSearchOption.StartsWith:
                        if (testLine.StartsWith(propertyName.ToUpper())) { results.Add(line); }
                        break;
                    case StringSearchOption.Contains:
                        if (testLine.Contains(propertyName.ToUpper())) { results.Add(line); }
                        break;
                    case StringSearchOption.EndsWith:
                        if (testLine.EndsWith(propertyName.ToUpper())) { results.Add(line); }
                        break;
                }
            }
        }
        catch
        {
            // Trap any exception that occurs in reading the file and return null.
            results = null;
        }
        finally
        {
            if (sr != null) {sr.Close();}
        }
    
        return results;
    }
    
  10. Após o método de GetPropertyValue , adicione o seguinte código para substituir o método de TryGetMember da classe de DynamicObject .O método de TryGetMember é chamado quando um membro de uma classe dinâmica é solicitado e nenhum argumento é especificado.O argumento de binder contém informações sobre o membro referenciado, e o argumento de result referencia o resultado retornado para o membro especificado.O método de TryGetMember retorna um valor Booleano que retorna true se o membro existe; aplicativo se não 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
    
    // Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
    public override bool TryGetMember(GetMemberBinder binder,
                                      out object result) 
    {
        result = GetPropertyValue(binder.Name);
        return result == null ? false : true;
    }
    
  11. Após o método de TryGetMember , adicione o seguinte código para substituir o método de TryInvokeMember da classe de DynamicObject .O método de TryInvokeMember é chamado quando um membro de uma classe dinâmica é solicitado através de argumentos.O argumento de binder contém informações sobre o membro referenciado, e o argumento de result referencia o resultado retornado para o membro especificado.O argumento de args contém uma matriz de argumentos que são passados para o membro.O método de TryInvokeMember retorna um valor Booleano que retorna true se o membro existe; aplicativo se não retorna false.

    A versão personalizada do método de TryInvokeMember espera que o primeiro argumento ser um valor enum de StringSearchOption que você definiu em uma etapa anterior.o método de TryInvokeMember espera o segundo argumento ser um valor Booleano.Se um ou ambos os argumento é valores válidos, eles são passados para o método de 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
    
    // Implement the TryInvokeMember method of the DynamicObject class for 
    // dynamic member calls that have arguments.
    public override bool TryInvokeMember(InvokeMemberBinder binder,
                                         object[] args,
                                         out object result)
    {
        StringSearchOption StringSearchOption = StringSearchOption.StartsWith;
        bool trimSpaces = true;
    
        try
        {
            if (args.Length > 0) { StringSearchOption = (StringSearchOption)args[0]; }
        }
        catch
        {
            throw new ArgumentException("StringSearchOption argument must be a StringSearchOption enum value.");
        }
    
        try
        {
            if (args.Length > 1) { trimSpaces = (bool)args[1]; }
        }
        catch
        {
            throw new ArgumentException("trimSpaces argument must be a Boolean value.");
        }
    
        result = GetPropertyValue(binder.Name, StringSearchOption, trimSpaces);
    
        return result == null ? false : true;
    }
    
  12. Salve e feche o arquivo.

Para criar um arquivo de texto de exemplo

  1. Clique com o botão direito do mouse no projeto e o ponto de DynamicSample a Adicionar, clique em Novo Item.Em o painel de Modelos Instalados , Geralselecione, e então selecione o modelo de Arquivo de Texto .Deixe o nome padrão do TextFile1.txt na caixa de Nome , clique em Adicionar.um novo arquivo de texto é adicionado ao projeto.

  2. Copie o texto a seguir para o arquivo TextFile1.txt.

    List of customers and suppliers
    
    Supplier: Lucerne Publishing (http://www.lucernepublishing.com/)
    Customer: Preston, Chris
    Customer: Hines, Patrick
    Customer: Cameron, Maria
    Supplier: Graphic Design Institute (http://www.graphicdesigninstitute.com/) 
    Supplier: Fabrikam, Inc. (http://www.fabrikam.com/) 
    Customer: Seubert, Roxanne
    Supplier: Proseware, Inc. (https://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 Module1.vb se você estiver usando Visual Basic ou arquivo de Module.vb se você estiver usando o visual C#.

  2. Adicione o seguinte código ao procedimento principal para criar uma instância da classe de 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 “” cliente.

    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
    
    dynamic rFile = new ReadOnlyFile(@"..\..\TextFile1.txt");
    foreach (string line in rFile.Customer)
    {
        Console.WriteLine(line);
    }
    Console.WriteLine("----------------------------");
    foreach (string line in rFile.Customer(StringSearchOption.Contains, true))
    {
        Console.WriteLine(line);
    }
    
  3. Salve o arquivo e pressione CTRL + f5 para compilar e executar o aplicativo.

Chamando uma biblioteca dinâmica de linguagem

O projeto seguir que você cria em acessos de este passo-a-passo uma biblioteca que foi escrito na linguagem IronPython dinâmico.Antes de criar o projeto, você deve ter IronPython 2.6.1 para .NET 4,0 instalado.você pode baixar IronPython 2.6.1 para .NET 4,0 de CodePlex.

Para criar uma classe dinâmica personalizado

  1. Em Visual Studio, no menu File, aponte para New e então clique em Project.

  2. Em a caixa de diálogo de Novo Projeto , no painel de Tipos de projeto , certifique-se que está selecionado Janelas .Aplicativo de Console Selecione no painel de Modelos .Em a caixa de Nome , o tipo DynamicIronPythonSample, e clique em OK.o novo projeto é criado.

  3. Se você estiver usando Visual Basic, clique com o botão direito do mouse no projeto de DynamicIronPythonSample e clique em Propriedades.Clique na aba References.Clique no botão Add.Se você estiver usando o visual C#, em Gerenciador de Soluções, clique com o botão direito do mouse na pasta de Referências e clique em Adicionar Referência.

  4. Em a guia de Procurar , navegue até a pasta onde as bibliotecas de IronPython são instaladas.Por exemplo, C:\Program Files\IronPython .NET 2,6 para 4,0.Selecione IronPython.dll, IronPython.Modules.dll, Microsoft.Scripting.dll, e bibliotecas de Microsoft.Dynamic.dll .Clique em OK.

  5. Se você estiver usando Visual Basic, edite o arquivo Module1.vb.Se você estiver usando o visual C#, edite o arquivo de Module.vb.

  6. Em a parte superior do arquivo, adicione o seguinte código para importar Microsoft.Scripting.Hosting e namespaces de IronPython.Hosting as bibliotecas de IronPython.

    Imports Microsoft.Scripting.Hosting
    Imports IronPython.Hosting
    
    using Microsoft.Scripting.Hosting;
    using IronPython.Hosting;
    
  7. Em o método principal, adicione o seguinte código para criar um novo objeto de Microsoft.Scripting.Hosting.ScriptRuntime para hospedar as bibliotecas de IronPython.O objeto de ScriptRuntime carrega o módulo random.py de biblioteca de IronPython.

    ' Set the current directory to the IronPython libraries.
    My.Computer.FileSystem.CurrentDirectory = 
       My.Computer.FileSystem.SpecialDirectories.ProgramFiles &
       "\IronPython 2.6 for .NET 4.0\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.")
    
    // Set the current directory to the IronPython libraries.
    System.IO.Directory.SetCurrentDirectory(
       Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + 
       @"\IronPython 2.6 for .NET 4.0\Lib");
    
    // Create an instance of the random.py IronPython library.
    Console.WriteLine("Loading random.py");
    ScriptRuntime py = Python.CreateRuntime();
    dynamic random = py.UseFile("random.py");
    Console.WriteLine("random.py loaded.");
    
  8. Depois que o código para carregar o módulo de random.py, adicione o seguinte código para criar uma matriz de inteiros.A matriz é passada para o método de shuffle módulo de random.py, que classes 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
    
    // Initialize an enumerable set of integers.
    int[] items = Enumerable.Range(1, 7).ToArray();
    
    // Randomly shuffle the array of integers by using IronPython.
    for (int i = 0; i < 5; i++)
    {
        random.shuffle(items);
        foreach (int item in items)
        {
            Console.WriteLine(item);
        }
        Console.WriteLine("-------------------");
    }
    
  9. Salve o arquivo e pressione CTRL + f5 para compilar e executar o aplicativo.

Consulte também

Referência

System.Dynamic

System.Dynamic.DynamicObject

dinâmico (referência de C#)

Conceitos

(Visual Basic) de vinculação antecipada e atrasada

Outros recursos

Usar o tipo dinâmico (C# Programming Guide)

Implementando interfaces dinâmicos (blog externa)