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, você pode criar e ExpandoObject 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 substituir os DynamicObject membros da classe 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
- Visual Studio 2022 versão 17.3 ou uma versão posterior com a carga de trabalho de desenvolvimento de área de trabalho .NET instalada. O SDK do .NET 7 é incluído quando você seleciona essa carga de trabalho.
Nota
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.
- Para o segundo passo a passo, instale o IronPython para .NET. Vá para a página de download para obter a versão mais recente.
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 ReadOnlyFile
e 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;
}
- Adicione o seguinte método
GetPropertyValue
à classeReadOnlyFile
. OGetPropertyValue
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 pelaReadOnlyFile
classe chamam oGetPropertyValue
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 GetPropertyValue
método, adicione o código a seguir para substituir o TryGetMemberDynamicObject método da 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 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 TryGetMember
método, adicione o código a seguir para substituir o TryInvokeMemberDynamicObject método da 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 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;
}
Guarde e feche o ficheiro.
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 seguinte texto para o ficheiro 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
Guarde e feche o ficheiro.
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 usa a vinculação tardia para chamar membros dinâmicos e recuperar linhas de texto que contêm a cadeia de caracteres "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 idiomas 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 e IronPython.Hosting
e Microsoft.Scripting.Hosting
das bibliotecas IronPython e do System.Linq
namespace.
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.