Compartilhar via


Passo a passo: criando e usando objetos dinâmicos em C#

Objetos dinâmicos expõem membros como propriedades e métodos em tempo de execução, em vez de em tempo de compilação. Objetos dinâmicos permitem que você crie objetos para trabalhar com estruturas que não correspondem a um tipo ou formato estático. Por exemplo, você pode usar um objeto dinâmico para referenciar o DOM (Modelo de Objeto de Documento HTML), que pode conter qualquer combinação de elementos e atributos de marcação HTML válidos. Como cada documento HTML é exclusivo, os membros de um documento HTML específico 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 GetProperty método do elemento. Para fazer referência ao id atributo do elemento <div id="Div1">HTML, primeiro você obtém uma referência ao <div> elemento e, em seguida, usa divElement.GetProperty("id"). Se você usar um objeto dinâmico, poderá referenciar o id atributo como divElement.id.

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

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

Você pode criar objetos dinâmicos personalizados usando as classes no System.Dynamic namespace. Por exemplo, você pode 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 a DynamicObject classe. Em seguida, você pode sobrescrever os membros da classe DynamicObject para fornecer funcionalidade dinâmica em tempo de execução.

Este artigo contém dois passo a passo independentes:

  • Crie um objeto personalizado que exponha dinamicamente o conteúdo de um arquivo de texto como propriedades de um objeto.
  • Crie um projeto que use uma IronPython biblioteca.

Pré-requisitos

Observação

Seu computador pode mostrar nomes ou locais diferentes 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ê tem 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 "Amostra". 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 enumeração de opções de pesquisa que especifica que a classe dinâmica deve pesquisar correspondências no início da linha, no final da linha ou em qualquer ponto da linha. O segundo argumento especifica que a classe dinâmica deve cortar espaços à esquerda e à direita de cada linha antes da pesquisa. Por exemplo, se o código de chamada especificar dynamicFile.Sample(StringSearchOption.Contains), a classe dinâmica procurará "Amostra" em qualquer lugar de uma linha. Se o código de chamada especificar dynamicFile.Sample(StringSearchOption.StartsWith, false), a classe dinâmica procurará "Amostra" no início de cada linha e não removerá espaços à esquerda e à direita. O comportamento padrão da classe dinâmica é pesquisar uma correspondência no início de cada linha e remover espaços à esquerda e à direita.

Criar uma classe dinâmica personalizada

Inicie o Visual Studio. Selecione Criar um novo projeto. Na caixa de diálogo Criar um novo projeto , selecione C#, selecione Aplicativo de Console e, em seguida, selecione Avançar. Na caixa de diálogo Configurar seu novo projeto , insira DynamicSample o nome do Projeto e selecione Avançar. Na caixa de diálogo Informações adicionais , selecione .NET 7.0 (Atual) para a Estrutura de Destino e, em seguida, selecione Criar. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto DynamicSample e selecione Adicionar>Classe. Na caixa Nome , digite ReadOnlyFilee selecione Adicionar. 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.

using System.IO;
using System.Dynamic;

O objeto dinâmico personalizado usa uma enumeração 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
}

Atualize a instrução de classe para herdar a DynamicObject classe, conforme mostrado no exemplo de código a seguir.

class ReadOnlyFile : DynamicObject

Adicione o seguinte código à classe ReadOnlyFile para definir um campo privado 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 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;
}
  1. Adicione o método a seguir GetPropertyValue à ReadOnlyFile classe. O GetPropertyValue método usa, como entrada, critérios de pesquisa e retorna as linhas de um arquivo de texto que correspondem a esses critérios de pesquisa. Os métodos dinâmicos fornecidos pela ReadOnlyFile classe chamam o GetPropertyValue método para recuperar seus respectivos resultados.
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;
}

Após o GetPropertyValue método, adicione o código a seguir para substituir o TryGetMember método da DynamicObject classe. O TryGetMember método é chamado quando um membro de uma classe dinâmica é solicitado e nenhum argumento é especificado. O binder argumento contém informações sobre o membro referenciado e o result argumento faz referência ao resultado retornado para o membro especificado. O TryGetMember método retorna um valor booliano que retorna true se o membro solicitado existir; caso contrário, retorna false.

// 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;
}

Após o TryGetMember método, adicione o código a seguir para substituir o TryInvokeMember método da DynamicObject classe. O TryInvokeMember método é chamado quando um membro de uma classe dinâmica é solicitado com argumentos. O binder argumento contém informações sobre o membro referenciado e o result argumento faz referência ao resultado retornado para o membro especificado. O args argumento contém uma matriz dos argumentos que são passados para o membro. O TryInvokeMember método retorna um valor booliano que retorna true se o membro solicitado existir; caso contrário, retorna false.

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

// 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;
}

Salve e feche o arquivo.

Criar um arquivo de texto de exemplo

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, em seguida, selecione o modelo arquivo de texto . Deixe o nome padrão de TextFile1.txt na caixa Nome e selecione Adicionar. Copie o texto a seguir 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

Salve e feche o arquivo.

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

No Gerenciador de Soluções, clique duas vezes no arquivo Program.cs . Adicione o código a seguir ao Main procedimento para criar uma instância da ReadOnlyFile classe 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 string "Cliente".

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);
}

Salve o arquivo e pressione Ctrl+F5 para compilar e executar o aplicativo.

Chamar uma biblioteca de linguagem dinâmica

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

Para criar uma classe dinâmica personalizada

No Visual Studio, selecione Arquivo>Novo>Projeto. Na caixa de diálogo Criar um novo projeto , selecione C#, selecione Aplicativo de Console e, em seguida, selecione Avançar. Na caixa de diálogo Configurar seu novo projeto , insira DynamicIronPythonSample o nome do Projeto e selecione Avançar. Na caixa de diálogo Informações adicionais , selecione .NET 7.0 (Atual) para a Estrutura de Destino e, em seguida, selecione Criar. Instale o pacote NuGet IronPython . Edite o arquivo de Program.cs . Na parte superior do arquivo, adicione o código a seguir para importar os namespaces Microsoft.Scripting.Hosting e IronPython.Hosting das bibliotecas IronPython e o namespace System.Linq.

using System.Linq;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;

No método Main, adicione o código a seguir para criar um novo Microsoft.Scripting.Hosting.ScriptRuntime objeto para hospedar as bibliotecas IronPython. O ScriptRuntime objeto carrega o módulo da biblioteca 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");
ScriptRuntime py = Python.CreateRuntime();
dynamic random = py.UseFile("random.py");
Console.WriteLine("random.py loaded.");

Após o código para carregar o módulo random.py, adicione o código a seguir para criar uma matriz de inteiros. A matriz é passada para o shuffle método do módulo random.py, que classifica aleatoriamente os valores na matriz.

// 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("-------------------");
}

Salve o arquivo e pressione Ctrl+F5 para compilar e executar o aplicativo.

Consulte também