Partilhar via


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

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. Os objetos dinâmicos permitem criar 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 fazer referência ao DOM (Document Object Model) 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 obtenha uma referência ao <div> elemento e, em seguida, use divElement.GetProperty("id"). Se você usar um objeto dinâmico, poderá fazer referência ao 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 fazer referência a um script dinâmico interpretado em tempo de execução.

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

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

Este artigo contém duas instruções 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 da 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 "Sample". A pesquisa não diferencia maiúsculas de minúsculas. A classe dinâmica também suporta dois argumentos opcionais. O primeiro argumento é um valor enum da opção de pesquisa que especifica que a classe dinâmica deve procurar 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 à esquerda e à direita de cada linha antes de pesquisar. Por exemplo, se o código de chamada especificar dynamicFile.Sample(StringSearchOption.Contains), a classe dinâmica procurará "Exemplo" em qualquer lugar de uma linha. Se o código de chamada especificar dynamicFile.Sample(StringSearchOption.StartsWith, false), a classe dinâmica procurará "Exemplo" no início de cada linha e não removerá espaços à esquerda e à direita. O comportamento padrão da classe dinâmica é procurar 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 selecione Avançar. Na caixa de diálogo Configurar seu novo projeto , digite DynamicSample o nome do projeto e selecione Avançar. Na caixa de diálogo Informações adicionais , selecione .NET 7.0 (Atual) para o Target Framework 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 System.IO namespaces e System.Dynamic .

using System.IO;
using System.Dynamic;

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

public enum StringSearchOption
{
    StartsWith,
    Contains,
    EndsWith
}

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

class ReadOnlyFile : DynamicObject

Adicione o seguinte código à ReadOnlyFile classe para definir um campo privado para o caminho do arquivo e um construtor para a ReadOnlyFile classe.

// 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 seguinte GetPropertyValue método à ReadOnlyFile classe. O GetPropertyValue método toma, 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 ReadOnlyFile classe chamam o GetPropertyValue método para recuperar seus respetivos 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 método GetPropertyValue, adicione o seguinte código para substituir o método TryGetMember da classe DynamicObject. 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 faz result referência ao resultado retornado para o membro especificado. O TryGetMember método retorna um valor booleano que retorna true se o membro solicitado existir, caso contrário, ele 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 método TryGetMember, adicione o seguinte código para substituir o método TryInvokeMember da classe DynamicObject. 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 faz result 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 booleano que retorna true se o membro solicitado existir, caso contrário, ele retorna false.

A versão personalizada do TryInvokeMember método espera que o primeiro argumento seja um valor do StringSearchOption enum que você definiu em uma etapa anterior. O TryInvokeMember método espera que o segundo argumento seja um valor booleano. 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 ficheiro 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 seguinte código ao Main procedimento para criar uma instância da ReadOnlyFile classe para o arquivo TextFile1.txt . O código utiliza vinculação tardia para chamar membros dinâmicos e recuperar linhas de texto que contêm a sequência "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 criar 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 selecione Avançar. Na caixa de diálogo Configurar seu novo projeto , digite DynamicIronPythonSample o nome do projeto e selecione Avançar. Na caixa de diálogo Informações adicionais , selecione .NET 7.0 (Atual) para o Target Framework e, em seguida, selecione Criar. Instale o pacote NuGet do IronPython . Edite o arquivo 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 de 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 criar e executar o aplicativo.

Ver também