Garantindo a consistência de uma Interface

by Israel Aece 17. February 2011 07:07

Imagine que você possui uma interface que descreve a base para alguma funcionalidade do seu sistema. Como sabemos, a ideia de isolarmos a definição em uma interface serve para facilitar os testes, diminuir o acoplamento e melhorar a estensibilidade.

Quando construímos um tipo, muitas vezes pensamos em como garantir que ele sempre fique em um estado consistente, para que seja utilizado pela aplicação sem qualquer problema. Mas como garantir a consistência de um tipo como uma interface? Interfaces não possuem qualquer implementação, e com isso não há como escrever qualquer código para validar parâmetros, garantia de estado, etc.

Com a criação da interface, também não temos controle de quantas implementações dela serão criadas. Deixar a responsabilidade de garantir a consistência para os implementadores, corre-se o risco de que um deles não se preocupe com isso, prejudicando o propósito para qual a interface foi criada.

A Microsoft recentemente publicou um projeto chamado Code Contracts, e que podemos utilizar uma funcionalidade dele para suavizar esse problema. Através dos atributos ContractClassForAttribute e ContractClassAttribute, conseguimos amarrar (e separar) a nossa interface à uma classe utilizada exclusivamente para validar as implementações, que analisará em runtime se as condições estão ou não sendo atentidas. Abaixo temos uma interface para um repositório de domínio, e logo em seguida, temos uma classe apenas para garantir a sua consistência.

[ContractClass(typeof(RepositoryContract))]
public interface IRepository
{
    T GetById<T>(Guid id) where T : AggregateRoot;

    void Save(AggregateRoot item);
}

[ContractClassFor(typeof(IRepository))]
internal sealed class RepositoryContract : IRepository
{
    public T GetById<T>(Guid id) where T : AggregateRoot
    {
        return default(T);
    }

    public void Save(AggregateRoot item)
    {
        Contract.Requires<ArgumentNullException>(item != null);
    }
}

Note que utilizamos o atributo ContractClassAttribute para apontar qual a classe que representa o contrato, e mais abaixo, utilizamos o atributo ContractClassForAttribute para indicarmos que a classe onde este atributo está sendo aplicado serve como contrato para a interface apontada nele. E, finalmente, um detalhe interessante é que a classe é definida como internal, evitando assim o acesso direto pelos consumidores da interface.

Tags: ,

C#

O Framework possibilita, a Linguagem facilita

by Israel Aece 29. October 2010 00:25

Desde a primeira versão do .NET Framework, várias funcionalidades foram construídas e as linguagens (aqui C# e VB.nET) facilitam o acesso as mesmas, tornando a vida do desenvolvedor muito mais simples. Para mostrar um exemplo simples, podemos perceber que grande parte de nós não utiliza o tipo Int32 para declarar um inteiro. Optamos pela keyword int. Grande parte de nós não utiliza o tipo Boolean para declarar um valor boleano. Optamos pela keyword bool.

Já no .NET Framework 2.0, a Microsoft introduziu no C# os iteradores, que evita a escrita explícita de classes que implementam as interfaces IEnumerable<T> e IEnumerator<T>. Tudo o que ela fez foi criar uma keyword chamada yield, que elimina toda essa necessidade, abstraindo a "complexidade" que esta implementação possui.

Para ter um exemplo mais recente, podemos avaliar as expressões lambdas. Elas nada mais são do que uma forma muito mais simples de se escrever (não de entender) delegates. Salvo a sintaxe de cada linguagem, a Microsoft está tornando tarefas complexas de serem realizadas em um modo bem mais simples de se fazer, ou seja, com novas essas keywords e um jeito diferente de se escrever o mesmo código, grande parte do trabalho complexo agora fica sob responsabilidade do compilador, que avalia e gera a saída necessária para tudo isso funcionar.

Entre as tarefas mais complexas que existem dentro do .NET Framework hoje, é a programação assíncrona. Ela não é nada trivial, pois exige um conhecimento razoável de como as coisas funcionam nos bastidores, o uso do par de métodos BeginXXX/EndXXX, das formas de capturar o resultado (callback ou poll), exceções que são disparadas, etc. Devido a essa complexidade toda, a programação assíncrona foi o alvo da Microsoft para tornar essa tarefa bem mais amena.

Apesar de isso já correr há algum tempo nos bastidores, a Microsoft anunciou hoje no PDC, um novo modelo de programação assíncrona, que permite a escrita do código assíncrono de forma tão simples quanto ao código síncrono. A partir de agora, tudo o que precisamos fazer é declarar a função como sendo assíncrona, e isso é feito através de uma nova keyword chamada async. Além disso, a função também poderá retornar um tipo predefinido que é a instância da classe Task<T>, que como o nome já sugere, representa uma tarefa que está sendo executada.

public async Task<decimal> CalcularSalarioAsync(string empregado)
{
    var resultado = await new ServicoDeSalario().CalcularAsync(empregado);

    return resultado;
}

Analisando o código acima, podemos perceber que também surgiu uma nova keyword: await. Apesar de parecer que ela irá bloquear a thread até que seja finalizado, não é isso o que acontece. Na verdade, quando o compilador encontrar essa keyword, o que ele fará é determinar que o que virá dali para baixo, até o final do método, será o callback que deverá ser disparado quando o processo assíncrono for finalizado.

A finalidade de facilitar isso, é fazer com que a programação assíncrona dentro do .NET Framework seja tão simples quanto a programação síncrona e, consequentemente, tornar as aplicações mais interativas quando falamos daquelas que exigem muitas interações de UI, ou tornando mais simples quando precisamos escrever alguma funcionalidade de forma assíncrona do lado do servidor, como é o caso de páginas/controllers assíncronos do ASP.NET e serviços em geral.

Explorarei mais detalhadamente essa funcionalidade em futuros artigos. Por agora, foi apenas um overview do que está por vir, e também mostrar que algumas complexidades são, aos poucos, absorvidas pelas linguagens. Da mesma forma que as facilidades anteriores que foram criadas dentro das linguagens, esta também será incorporada, mas vale ressaltar que continua sendo importante o seu entendimento interno da mesma forma que é importante conhecer delegates, caso contrário, expressões lambdas serão completamente estranhas.

Tags: , ,

.NET Framework | Async | C#

Analisando a exceção ContractException

by Israel Aece 15. August 2010 21:17

A partir de agora, durante a escrita do nosso código, podemos recorrer ao Code Contracts, que é uma biblioteca que está sendo desenvolvida pela Microsoft, e que permite trabalhar com condições e garantir com que elas sejam atendidas durante a execução ou até mesmo de forma estática. Caso alguma das regras impostas seja violada, uma exceção será disparada, caracterizando um bug no sistema que consome este componente. O uso desse novo recurso tende a diminuir consideravelmente o uso do código if-then-throw.

A exceção que é disparada é do tipo ContractException e, propositalmente, ela foi criada como internal. Isso evita que se crie tratadores de erro que capture este tipo de exceção, e com isso burle o processo de verificação que é realizado por essa biblioteca. A aplicação que consome a classe deve se preocupar apenas em capturar exceções tradicionais (ArgumentNullException, IndexOutOfRangeException, etc.), pois enquanto houver exceções do tipo ContractException sendo disparadas, provavelmente o consumidor não está passando as informações da forma correta.

Há alguns momentos em que gostaríamos de mudar este comportamento, como por exemplo, eliminar essa validação durante a escrita de algum teste (isso envolve outra discussão, que é TDD com DbC). Para exemplificar, considere o código abaixo, que possui uma condição pré (Requires) e outra pós (Ensures), que recorre ao Code Contracts para validar e garantir que as informações são passadas da forma correta para o método Creditar e também garante o estado da classe ContaBancaria, após a execução deste mesmo método.

public class ContaBancaria
{
    public decimal Saldo { get; private set; }

    public ContaBancaria(decimal saldo)
    {
        this.Saldo = saldo;
    }

    public void Creditar(decimal quantia)
    {
        Contract.Requires(quantia > 0, "A quantia para deposito deve ser maior que 0");
        Contract.Ensures(Contract.OldValue(this.Saldo) + quantia == this.Saldo);

        this.Saldo += quantia;
    }
}

Se criarmos um código para consumir essa classe e, consequentemente, efetuar um crédito com valor negativo, teremos uma exceção do tipo ContractException. Para contornar esse comportamento, podemos recorrer ao evento estático ContractFailed da classe Contract. Esse evento define o argumento do tipo ContractFailedEventArgs, que expõe alguns membros interessantes, e alguns deles estão listados abaixo:

  • Condition: Uma string com a condição que não foi atentida.
  • FailureKind: Uma das opções exposta pelo enumerador ContractFailureKind, indicando se é uma condição pré, pós ou invariante.
  • Message: Uma string que representa a mensagem que descreve o problema.
  • OriginalException: Retorna a instância da exceção que causou o evento, que é utilizado quando você utiliza métodos que, por questões de compatibilidade, dispara exceções diferentes de ContractException.
  • SetHandled: Método que quando invoca, suprime o disparo da exceção que violou o contrato.
  • SetUnwind: Ao contrário do método anterior, quando invocado ele dispara a exceção ContractException depois que o tratador do evento ContractFailed é encerrado.

Com os membros que vimos acima, podemos agora ter acesso ao tipo do problema que ocorreu, e ainda conseguir burlar o problema de verificação que é realizado pelo Code Contracts. Abaixo temos um exemplo de como podemos proceder para fazer isso funcionar, ou seja, invocando o método SetHandled para que erros que violam o contrato não sejam mais entregues para o código consumidor:

static void Main(string[] args)
{
    Contract.ContractFailed += (sender, args) =>
    {
        Console.WriteLine("{0} - {1}", args.FailureKind, args.Condition);
        args.SetHandled();
    };

    new ContaBancaria(1000).Creditar(-100);
}

Tags:

C#

Omitindo tipos genéricos durante a construção

by Israel Aece 10. August 2010 22:38

Os Generics trouxeram um grande poder às linguagens .NET. O tipos genéricos podem ser utilizados por toda a classe onde ele está sendo criado e, consequentemente, podemos utilizar em seus construtores. O maior problema da criação de objetos que exigem um parâmetro genérico, é a necessidade de especificarmos esses tipos durante a sua construção, ou seja, o construtor não é capaz de inferir os tipos, o que torna o código um pouco ilegível. Para exemplificar, considere o seguinte código:

public class ProxyManager<TChannel, TBinding>
{
    private TChannel _channel;
    private TBinding _binding;

    public ProxyManager(TChannel channel, TBinding binding)
    {
        this._channel = channel;
        this._binding = binding;
    }

    //Outros Membros
}

Durante a sua criação, é necessário especificarmos os tipos genéricos para depois conseguir parametrizar o construtor com os valores efetivos. Se repararmos o código abaixo, note que não podemos omitir o que está entre os caracteres < e >, mesmo que construtores são uma espécie de método, eles não possibilitam a omissão dos mesmos, assim como acontece nos métodos genéricos.

var manager = 
    new ProxyManager<ServicoDeUsuariosClient, NetTcpBinding>(
        new ServicoDeUsuariosClient(), 
        new NetTcpBinding());

Para melhorar esse código e torná-lo mais simples de consumir a classe, podemos recorrer a criação de uma nova classe, que conterá um método estático que aceita exatamente os parâmetros genéricos exigidos pelo construtor da classe ProxyManager<TChannel, TBinding>, e o retorno será a própria classe criada, uma espécie de factory. O que acontece aqui é que todo o código burocrático acaba ficando dentro deste método.

public static class ProxyManager
{
    public static ProxyManager<TChannel, TBinding> Create<TChannel, TBinding>(TChannel channel, TBinding binding)
    {
        return new ProxyManager<TChannel, TBinding>(channel, binding);
    }
}

Com isso, a criação de um novo ProxyManager, se resume simplesmente ao código que vemos abaixo:

var manager = 
    new ProxyManager.Create(new ServicoDeUsuariosClient(), new NetTcpBinding());

Tags:

C#

Detectando mudanças em objetos

by Israel Aece 22. June 2010 12:14

Há uma porção de funcionalidades dentro do .NET Framework, que podemos incorporar em nossos tipos, para enriqucê-los ainda mais em nível de comportamento. Essas funcionalidades predefinidas, já trazem recursos extremamente interessantes, que com pouco de código extra que utilizamos para "rechear" os pontos customizados, poderemos poupar muitas e muitas linhas de código se fossemos fazer isso manualmente.

Entre as várias funcionalidades que existem e que já falei bastante por aqui, uma delas é a capacidade que temos de dectectar mudanças que acontecem no estado (propriedades) das nossas classes. Geralmente as classes possuem propriedades que podem ser alteradas durante a sua execução, sendo essa alteração realizada através do bloco Set da mesma, ou através de algum método que a manipula internamente.

Por algum motivo, se quisermos detectar que alguma mudança está acontecendo ou já aconteceu, podemos implementar nesta classe as interfaces INotifyPropertyChanging e INotifyPropertyChanged que estão debaixo do namespace System.ComponentModel. Cada uma delas é utilizada para interceptar momentos diferentes, ou seja, a primeira deve ser utilizada quando queremos ser notificados antes da mudança, enquanto a segunda deverá ser utilizada para notificar quando a mudança já aconteceu.

A primeira interface, INotifyPropertyChanging, fornece um único membro, que é o evento PropertyChanging. Já a segunda, INotifyPropertyChanged, disponibiliza um outro evento chamado PropertyChanged. Ambas interfaces podem ser implementadas em classes que você deseja monitorar as alterações que podem acontecer em suas respectivas propriedades. Com isso, podemos permitir aos consumidores desta classe, serem notificados antes e depois da mudança acontecer, podendo assim tomar alguma decisão em cima disso.

Como podemos notar no código abaixo, temos uma classe chamada Cliente, que por sua vez, contém apenas uma única propriedade chamada Nome. Para qualquer evento que você crie, o ideal é criar um método que encapsule a regra para a construção dos parâmetros e o disparo dele, para evitar redundâncias pelo código. Para isso, foram criados dois métodos auxiliares, onde cada um deles encapsula a chamada para o evento que ele gerencia. Note que a atribuição do valor ao membro interno da classe, somente se dá caso o valor que chega para ela seja diferente do qual ela possui, justamente porque não faz sentido notificar alguém que a propriedade foi mudada, mas que efetivamente não foi. É importante notar também que a alteração que será feita na propriedade está envolvida pela chamada dos eventos, ou seja, antes da alteração disparamos o evento PropertyChanging, e depois que a alteração foi realizada, disparamos o evento PropertyChanged.

public class Cliente : INotifyPropertyChanging, INotifyPropertyChanged
{
    private string _nome;

    public string Nome
    {
        get
        {
            return this._nome;
        }
        set
        {
            if (value != this._nome)
            {
                this.OnPropertyChanging("Nome");
                this._nome = value;
                this.OnPropertyChanged("Nome");
            }
        }
    }

    public event PropertyChangingEventHandler PropertyChanging;

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanging(string propertyName)
    {
        if (this.PropertyChanging != null)
            this.PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Com isso, ao construir um objeto do tipo Cliente, definimos a sua propriedade Nome como "Israel". Em seguida, nos vinculamos aos eventos PropertyChanging e PropertyChanged, para sermos notificados caso qualquer alteração aconteça nas propriedades deste objeto. Tudo o que estamos fazendo no código abaixo, é escrevendo na tela a notificação da alteração da propriedade Nome. Finalmente, quando alteramos a propriedade Nome de "Israel" para "Israel Aece", notamos que as mensagens de notificação aparecerão na tela.

Cliente c = new Cliente() { Nome = "Israel" };

c.PropertyChanging += 
    (sender, e) => Console.WriteLine("Alterando a propriedade '{0}'.", e.PropertyName);

c.PropertyChanged +=
    (sender, e) => Console.WriteLine("Propriedade '{0}' alterada.", e.PropertyName);

c.Nome = "Israel Aece";

Assim como existe essas interfaces que agregam às nossas classes, a possibilidade de serem monitoradas quando alguma mudança acontecer, também há uma nova interface chamada INotifyCollectionChanged (namespace System.Collections.Specialized), que como o nome sugere, permite adicionar à uma coleção, a possibilidade de monitoramento da mesma, onde seremos notificados quando ela for modificada, ou seja, quando elementos forem adicionados ou removidos. Essa interface fornece um único membro, que é o evento CollectionChanged.

Esse evento faz uso de um parâmetro do tipo NotifyCollectionChangedEventArgs, que expõe algumas propriedades interessantes, como por exemplo: Action, NewItems e OldItems. O primeiro deles, retorna uma das opções do enumerador NotifyCollectionChangedAction, dizendo qual foi a ação que aconteceu. Já a propriedade NewsItems, disponiliza um objeto do tipo IList, contendo os novos itens que foram adicionados, enquanto a propriedade OldItens, retorna o mesmo tipo da propriedade anterior, mas com os objetos que foram removidos da coleção.

Essa interface nos permite criar uma coleção que pode ser monitorada quando os elementos dela são manipulados. Felizmente, a Microsoft já adicionou uma coleção genérica chamada ObservableCollection<T>, que está debaixo do namespace System.Collections.ObjectModel, já implementada com essa funcionalidade.

É importante dizer que quando estamos falando no monitoramento de modificações em uma coleção, estamos atentos aos itens que ela armazena, se novos são inseridos, se outros são removidos, alterados, etc. Se uma propriedade de um objeto que está dentro dela for alterada, nada acontecerá à coleção. Como exemplo de uso, podemos visualizar o código abaixo, que cria uma instância desta coleção, definindo o tipo T como sendo Cliente. Antes de começarmos a manipular a coleção, vamos nos vincular ao evento CollectionChanged, para sermos notificados quando novos itens forem adicionados ou removidos.

static void Main(string[] args)
{
    ObservableCollection<Cliente> clientes = new ObservableCollection<Cliente>();
    clientes.CollectionChanged += ColecaoAlterada;

    clientes.Add(new Cliente() { Nome = "Israel" });
    clientes.Add(new Cliente() { Nome = "Claudia" });
    clientes.Add(new Cliente() { Nome = "Virginia" });
}

static void ColecaoAlterada(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
        VisualizarClientes("Cliente(s) Adicionado(s)", e.NewItems);

    if (e.Action == NotifyCollectionChangedAction.Remove)
        VisualizarClientes("Cliente(s) Removido(s)", e.OldItems);
}

static void VisualizarClientes(string titulo, IList itens)
{
    if (itens != null && itens.Count > 0)
    {
        Console.WriteLine(titulo);

        foreach (var item in itens)
            Console.WriteLine("\t{0}", item);
    }
}

Ao executar o código acima, o método ColecaoAlterada será disparado três vezes, sendo uma para cada novo cliente que está sendo adicionado à coleção. Apesar de não estar sendo utilizado aqui, a classe ObservableCollection<T> também implementa a interface INotifyPropertyChanged, que tem a finalidade de monitorar duas propriedades, sendo elas: Items e Count, que são as principais propriedades de qualquer coleção.

Observação: Inicialmente os tipos que vimos aqui para monitoramento de coleções, foram criados para atender ao Windows Presentation Foundation, e justamente por isso, também podem ser encontrados dentro do assembly WindowsBase.dll. A partir da versão 4.0 do .NET Framework, a Microsoft trouxe esses tipos para dentro do assembly System.dll, que nos permite utilizá-los por qualquer tipo de aplicação, sem a necessidade de referenciar diretamente um assembly de uma tecnologia específica.

Conclusão: Vimos no decorrer deste artigo como podemos incorporar em nossas classes a funcionalidade para detectar mudanças, recorrendo à recursos do próprio .NET Framework. Grande parte do que vimos neste artigo, serve como base para grandes funcionalidades que estão espalhados por toda a plataforma .NET, como é o caso do databinding do WPF, consumo de serviços WCF (Data Services), entre outros. A ideia aqui foi apresentar, de uma forma "crua", essas funcionalidades, para mais tarde abordar outros recursos expostos pelo .NET Framework que fazem uso disso, e que já assumirão o conhecimento que vimos aqui.

Tags: ,

.NET Framework | C#

Evento de Tecnologia em Hortolândia

by Israel Aece 25. May 2010 21:36

No próximo dia 01 de junho (terça-feira) acontecerá um evento na UNASP Hortolândia (Centro Universitário Adventista de São Paulo), na cidade de Hortolândia. Para quem é de Campinas e região, este evento acontecerá na sede da universidade, localizada na Rua Pr. Hugo Gegembauer, 265, Parque Hortolândia, à partir das 19:45. Eu palestrarei sobre o Visual Studio 2010 e o .NET Framework 4.0. É importante dizer que a palestra será de nível 100, que além de abordar superficialmente algumas das principais funcionalidades desta nova versão, falaremos um pouco também sobre algumas tecnologias que já existem e estão à disposição desde as versões anteriores. Abaixo temos a descrição da palestra:

Título: Visual Studio 2010 e .NET Framework 4.0
Palestrante: Israel Aece
Descritivo: Esta palestra tem a finalidade de exibir um “tour” sobre a plataforma .NET, e a principal ferramenta que utilizamos para desenvolver aplicações para ela, que é o Visual Studio. A ideia é demonstrar rapidamente a história e a evolução do .NET Framework até a versão 4.0, incluindo assuntos como as linguagens de programação (C# e VB.NET), acesso à dados e aplicações para internet (WebForms, MVC e Silverlight). Logo após, vamos analisar de forma superficial as novidades que estão sendo incluídas na IDE do Visual Studio 2010 e que dão suporte ao desenvolvimento de qualquer tipo de aplicação sobre a plataforma .NET.

Tags: , , ,

C# | Data | General | WCF

Community Launch em Campinas

by Israel Aece 15. March 2010 22:38

No próximo dia 20 de março acontecerá um evento chamado de Community Launch. Esse evento será espalhado por todo o Brasil, onde cada região criará o evento e abordará os principais produtos da Microsoft que estarão sendo lançados neste ano de 2010, a saber: Visual Studio 2010, Windows Server 2008 R2SQL Server 2008 R2.

Para quem é de Campinas e região, este evento acontecerá na Universidade UNIP, localizada no bairro Swift, à partir das 09:00 da manhã. Caso você não saiba exatamente onde ela está localizada, consulte este endereço para saber como chegar até lá. Entre as várias palestras, eu sou o responsável por falar sobre Visual Studio 2010 e .NET Framework 4.0. É importante dizer que a palestra será de nível 100, que além de abordar superficialmente algumas das principais funcionalidades desta nova versão, falaremos um pouco também sobre algumas tecnologias que já existem e estão à disposição desde as versões anteriores. Abaixo temos a descrição da palestra:

Título: Visual Studio 2010 e .NET Framework 4.0
Palestrante: Israel Aece
Descritivo: Esta palestra tem a finalidade de exibir um “tour” sobre a plataforma .NET, e a principal ferramenta que utilizamos para desenvolver aplicações para ela, que é o Visual Studio. A ideia é demonstrar rapidamente a história e a evolução do .NET Framework até a versão 4.0, incluindo assuntos como as linguagens de programação (C# e VB.NET), acesso à dados e aplicações para internet (WebForms, MVC e Silverlight). Logo após, vamos analisar de forma superficial as novidades que estão sendo incluídas na IDE do Visual Studio 2010 e que dão suporte ao desenvolvimento de qualquer tipo de aplicação sobre a plataforma .NET.

IMPORTANTE: Apesar do evento ser gratuito, para poder participar é necessário efetuar o cadastro aqui.

Tags: , , ,

.NET Framework | C# | Data | General | VB.NET

Adicionando Membros em Tempo de Execução

by Israel Aece 4. October 2009 20:47

Como sabemos, o C# 4.0 (que virá junto com o Visual Studio .NET 2010) já trará alguns aspectos de linguagens dinâmicas, que permitem a avaliação/checagem de um membro somente em tempo de execução. Para suportar esta funcionalidade, um novo "tipo" foi criado, conhecido como "dynamic". Ao declarar uma variável do tipo "dynamic", a checagem de existência de um determinado membro não acontecerá estaticamente, ou seja, independentemente se ele exista ou não, você somente saberá isso em tempo de execução.

Com este tipo especial, você somente conseguirá acessar os membros que, eventualmente, já existam. Mas e como você pode proceder, se quiser construir um tipo dinamicamente? É aqui que entra em cena a classe ExpandoObject (namespace System.Dynamic). Ao instanciar essa classe, você poderá criar tipos dinamicamente, definindo novas propriedades e métodos para este tipo. Para que isso funcione adequadamente, você precisará atribuir a instância desta classe à uma variável do tipo "dynamic", caso contrário, como vimos acima, a checagem será efetuada durante a compilação, o que não permitirá a compilação. O código abaixo ilustra a utilização desta nova classe:

dynamic obj = new ExpandoObject();
obj.Nome = "Israel";
obj.Endereco = new ExpandoObject();
obj.Endereco.Cidade = "Valinhos";
obj.AlgumMetodo = new Action<string>(s => Console.WriteLine(s));

Console.WriteLine(obj.Endereco.Cidade);
obj.AlgumMetodo("Teste");

Como podemos notar, instanciamos a classe ExpandoObject para uma variável definida como dinâmica. Depois disso, quando queremos criar "sub-tipos", basta instanciar uma nova classe ExpandoObject para ele, e seguir criando os novos membros a partir dali. Métodos também podem ser criados, e você pode recorrer a algum delegate já existente para definir a ação a ser executada quando ele for invocado.

Na verdade, esses membros não são incluídos dentro da classe ExpandoObject. A medida que você vai criando estes membros, ele irá armazenando em um dicionário, e quando requisitado, extrai e o executa. Essa funcionalidade é disponibilizada através da Interface IDynamicMetaObjectProvider. Acredito que a performance deva ser mais lenta do que o binding estático, mas é um preço que se deve pagar quando quiser interoperar com linguagens dinâmicas que, além da interoperabilidade com o mundo COM é, ao meu ver, os principais cenários para códigos deste tipo.

Tags:

.NET Framework | C#

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Host