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#

Utilizando Generics em Serviços

by Israel Aece 9. July 2009 09:31

Uma das grandes desilusões ao utilizar o WCF, é não conseguir utilizar tipos de dados genéricos nos serviços. Generics são tipos de dados exclusivos do .NET Framework, e utilizá-los viola os princípios da orientação a serviços, já que podem existir linguagens que não suportam essa funcionalidade. É importante dizer que isso não é uma limitação do WCF, mas sim do WSDL, que é o documento utilizado para expor os metadados para os consumidores.

O Visual Studio .NET/compilador não vão proibí-lo de utilizá-los nos contratos. O problema será na exposição das informações (via WSDL) para o cliente e, consequentemente, o proxy gerado possuirá tipos "estranhos". Por exemplo, se uma operação do contrato retornar ou receber um tipo genérico como Teste<int>, ao gerar o proxy, ele irá criar um tipo (classe) chamado TesteOfInt, substituindo os parâmetros genéricos do mesmo, pelo tipo especificado na operação. Isso pode piorar um pouco se o parâmetro genérico informado for uma classe, como por exemplo Teste<OutraClasse>, resultando no seguinte tipo do lado do cliente: TesteOfOutraClasseKdjwuy4p, ou seja, acrescentando uma informação randômica para evitar eventuais conflitos com outros tipos no mesmo contrato.

Felizmente você pode sobrescrever esse comportamento, definindo a propriedade Name da atributo DataContractAttribute. Nela você pode especificar o formato do nome que deseja expor no WSDL. Se notarmos no primeiro exemplo abaixo, o parâmetro {0} será substituído pelo tipo genérico especificado. Caso a classe Teste suportasse mais do que um parâmetro genérico, então você pode também especificá-los para compor o nome, assim como mostrado no segundo exemplo.

[DataContract(Name = "TesteCom{0}")]
public class Teste<T> { }

[DataContract(Name = "TesteComTipo{0}EComChave{1}")]
public class Teste<T, D> { }

Um outro ponto importante é com relação as coleções. Elas também são características da plataforma, e não devem ser expostas além do serviço. Ao utilizar coleções que implementam direta ou indiretamente as Interfaces IEnumerable<T>, ICollection<T> ou IList<T>, o WCF automaticamente irá convertê-las em um array do tipo especificado no parâmetro genérico (<T>), facilitando a interoperabilidade com outras plataformas.

Ainda falando em coleções, ao criar uma coleção customizada, você poderá fazer uso do atributo CollectionDataContractAttribute, permitindo customizar o nome do tipo da coleção (através da propriedade Name) a ser colocado no WSDL e, consequentemente, criado no cliente (trabalhando da mesma forma que a propriedade Name do atributo DataContractAttribute). Ao utilizar este atributo, ainda temos a garantia de que o WCF verificará a existência do método Add durante a carga do serviço, e não existindo, uma exceção do tipo InvalidDataContractException será lançada. Este método se faz necessário para remontar a coleção durante a deserialização da mensagem.

Como dito acima, as coleções são características da plataforma, e não devem propagar além dos limites do serviço. Mas em algumas situações, isso pode ser interessante. Quando você está compartilhando tipos entre o cliente e o serviço (exige .NET/WCF presente dos dois lados), você pode optar por criar o proxy respeitando e preservando essas coleções. Para que isso seja possível, basta você utilizar a opções /reference/collectionType do utilitário svcutil.exe. A primeira opção determina o Assembly (reference) onde está a coleção, enquanto a segunda opção determina qual é a coleção. É importante dizer que este recurso também está disponível quando a criação do proxy é feita pela IDE do Visual Studio .NET.

Tags: , ,

WCF

Por dentro da Base Class Library

by Israel Aece 23. February 2008 01:00

A Base Classe Library (também conhecida como BCL) é um conjunto de classes que o .NET disponibiliza para todas as linguagens que rodam sob o .NET Framework. Essa base encapsula várias funcionalidades que tornam o trabalho dos desenvolvedores muito mais fácil. As classes contidas dentro da BCL é comum para qualquer tipo de aplicação, ou seja, independentemente de tecnologia (ASP.NET, Windows Forns, WPF, etc.), você poderá consumir essas classes que, representam tarefas que são comumente utilizadas. A imagem abaixo exibe onde a BCL está encaixada dentro da plataforma .NET.

Figura 1 - Base Class Library (BCL).

A versão 2.0 adicionou novas tipos e namespaces, enriquecendo ainda mais esta estrutura. Essas classes vão desde novas coleções (tipadas) até novos namespaces, como é o caso do System.Transactions. Apesar do .NET Framework estar em sua versão 3.5, ele utiliza o .NET 2.0 como seu núcleo. A figura abaixo ilustra perfeitamente a posição do .NET 2.0 dentro do .NET 3.X.

Figura 2 - Gráfico que exibe a posição do .NET 2.0.


A BCL é composta por vários namespaces e, através dos capítulos abaixo, veremos detalhadamente cada um dos principais deles. A idéia é abordar o conteúdo mais útil ao dia-à-dia, mostrando exemplos em Visual Basic .NET e Visual C#. Sendo assim, nem todas as classes/funcionalidades serão cobertas aqui mas, para isso, poderá recorrer ao MSDN Library.

ATENÇÃO: Os arquivos estão em formato XPS. Caso não tenha o visualizador, você poderá baixá-lo aqui.

Conteúdo

  • Capítulo 1 – Tipos de dados e Interfaces Este capítulo abordará a arquitetura de tipos fornecido pelo .NET Framework, onde na primeira parte do capítulo, será abordado os tipos padrões padrões e veremos como identificar se trata-se de um tipo valor ou referência. Além disso, analisaremos um problema grave, deixado de lado por muitos desenvolvedores, que é a questão do boxing e unboxing. Ainda nessa primeira parte, analisaremos alguns novos tipos introduzidos nesta versão do .NET Framework, em principal, os Generics. Na segunda e última parte do mesmo, vamos abordar as várias Interfaces que estão disponíveis para serem implementados em tipos customizados, fornecendo funcionalidades adicionais ao tipo criado.

  • Capítulo 2 – Trabalhando com Coleções As coleções são componentes importantes em qualquer tipo de aplicação e, para isso, esse capítulo abordará extensamente o uso das mesmas, começando pelas coleções primárias, fornecidas desde as primeiras versões do .NET Framework até as novas coleções, introduzidas na versão 2.0 do .NET Framework, quais fazem uso dos Generics. Além das coleções, analisaremos as Interfaces disponíveis para podermos estender as funcionalidades existentes e customizarmos para o nosso cenário.
  • Capítulo 3 – Utilização de Assemblies Um Assembly é a menor unidade de reutilização, segurança e controle de versão. O Assembly é algo importante que deve ser analisado cuidadosamente, pois toda aplicação .NET depois de compilada gerará um Assembly. Este capítulo abordará a sua criação desde um utilitário de linha de comando até o Visual Studio .NET. Além disso, abordaremos também outros assuntos relacionados a Assemblies, como por exemplo, strong names, GAC (Global Assembly Cache), instaladores e arquivos de configuração.
  • Capítulo 4 – Monitoramento e depuração de aplicações Toda e qualquer aplicação necessita de algum tipo de monitoramento de seu código para detectar possíveis problemas que possam acontecer e que devem ser analisados. O .NET Framework fornece várias classes que ajudam nesse monitoramento e, este capítulo, é responsável por apresentar essas classes que vão desde a manipulação do Event Log do Windows até classes que interagem com o WMI - Windows Management Instrumentation.
  • Capítulo 5 – Manipulando o sistema de arquivos Grande parte das aplicações comerciais que temos atualmente manipulam arquivos. Esses arquivos são arquivos de bancos, arquivos de parceiros e fornecedores que servem para troca de informações. Enquanto os XML Web Services ainda não são uma realidade para muitas empresas, a manipulação de arquivos e seus respectivos conteúdos é ainda muito utilizado. Tendo esse cenário, o capítulo em questão abordará as principais classes contidas dentro do namespace System.IO para exemplificar e facilitar a manipulação de arquivos do disco e streams de dados.
  • Capítulo 6 – Serialização A serialização de dados é cada dia mais utilizada em aplicações. Por mais que isso aconteça nos bastidores, esse capítulo abordará desde o seu conceito até como implementá-la; e ainda, em seus diversos formatos, utilizando as classes fornecidas pelo .NET Framework 2.0. Além disso, analisaremos classes e Interfaces que temos disponíveis, que proporcionaram o processo de serialização e deserialização mais flexível, onde podemos customizar e interceptar cada um desses processos de acordo com a nossa necessidade.
  • Capítulo 7 – Globalização de Aplicações Cada vez mais se desenvolve softwares que podem ser acessados por várias pessoas de diferentes idiomas e de diferentes locais do mundo. Tendo esse cenário, é importante que a aplicação que estamos desenvolvendo seja possível ao usuário poder customizar o idioma que deseja visualizar os dados e ainda, poder criar a aplicação independente de qualquer cultura. Essa capítulo tem justamente essa finalidade, ou seja, de exibir o que o .NET Framework é capaz de fazer para atender essa necessidade que, torna-se cada vez mais comum.
  • Capítulo 8 – Criptografia Criptografia de dados é um ponto muito importante nos mais diversos tipos de aplicações. Geralmente, em aplicações onde alguns dos dados são muito sigilosos, como é o caso de aplicações financeiras, quais mantém os dados de seus clientes, é necessário que se mantenha esses dados seguros pois, se esses dados cairem em mãos erradas, essas pessoas com más intenções, não consigam entender e/ou recuperar esses dados em sua forma legível. Esse capítulo abordará extensamente as classes responsáveis por criptografia e hashing que o .NET Framework disponiliza, bem como utilizá-las e como aplicá-las ao dia-à-dia.
  • Capítulo 9 – Utilizando Code Access Security – CAS Toda aplicação que utiliza o Common Language Runtime (CLR) obrigatoriamente deve interagir com o sistema de segurança do mesmo. Quando a aplicação é executada, automaticamente é avaliado se ela tem ou não determinados privilégios. Dependendo das permissões que a aplicação tem, ela poderá rodar perfeitamente ou gerar erros relacionados a segurança. Code Access Security (também conhecido como CAS), é um mecanismo que ajuda limitar/conceder o acesso que o código que está querendo realizar, protegendo recursos e operações. Este capítulo abordará como utilizar o CAS, que é fornecido juntamente com o SDK do .NET Framework e, como configurar devidamente a aplicação para evitar problemas relacionados a segurança.
  • Capítulo 10 – Envio de Mensagens (E-mails) Envio de e-mails é muito comum em qualquer tipo de aplicação, seja ela uma aplicação para internet, uma aplicação para Windows ou até mesmo serviços que rodam sem uma intervenção do usuário. O .NET Framework fornece um namespace contendo classes e muitos outros tipos que podemos utilizar nas aplicação para habilitar o envio de e-mails e, conseqüentemente, torná-las muito mais dinâmicas e inteligentes.
  • Capítulo 11 – Criando Serviços do Windows Os Serviços do Windows (Windows Services), permitem-nos criar aplicações que rodam em “background” no sistema operacional. Estes serviços podem ser automaticamente inicializados quando o sistema operacional inicializar, podendo ainda ser pausado e reinicializado, sem apresentar nenhuma interface com o usuário. Esses serviços são ideais para ser usado em servidores ou em funcionalidades de longa duração que necessitem ser executadas de forma totalmente independente, sem a intervenção de um usuário. O capítulo corrente abordará desde a sua criação, depuração e instalação do mesmo.
  • Capítulo 12 – Interoperabilidade com componentes COM A Microsoft criou a plataforma .NET e, em pouco tempo, essa plataforma foi adotada por muitas e muitas empresas. Algo importante é que muitas dessas empresas, já tinham componentes COM que eram utilizados em massa nas aplicações e que são inviáveis para serem reescritos imediatamente. Felizmente a Microsoft pensou no legado e possibilita a interoperabilidade de componentes COM, interagindo com aplicações baseadas na plataforma .NET e vice-versa. Este capítulo mostrará os passos necessários para efetuar essa interoperabilidade entre as novas aplicações e o que já existe em código legado.
  • Capítulo 13 – Reflection Reflection é a habilidade de extrair informações de metadados de um determinado tipo, ou seja, quais parâmetros, métodos, entre outros membros um determinado tipo possui. Isso torna a aplicação bastante flexível, onde podemos extrair informações necessárias para podermos customizar e automatizar a criação de ferramentas e utilitários que auxiliam os próprios desenvolvedores. Além disso, permite a criação em runtime de Assemblies e como instanciar classes via programação. Esse capítulo propõe-se a explicar como criar esse tipo de funcionalidade dentro da aplicação.
  • Capítulo 14 – Threading A criação de threads permitem aumentar consideravelmente a performance das aplicações. Elas fornecem a habilidade de conseguirmos delegar processamentos em diversas unidades de execução, aumentando a capacidade de processamento de uma aplicação. Mas utilizando isso de forma errada, poderá piorar ao invés de melhorar, consumindo mais recursos do que o necessário, tendo um comportamento inesperado e retornando valores diferentes do esperado. O .NET Framework fornece várias classes que podemos utilizar para criação e gerenciamento de threads, bloqueio de recursos em um ambiente multi-threading e sincronização. Este capítulo irá ajudá-lo a conhecer alguns problemas existentes em aplicações que fazem o uso de threads e como contorná-los.

Referências Bibliográficas

  • Code Complete – Second Edition
    Autor: Steve McConnell
    Editora: Microsoft Press
    ISBN: 0-7356-1967-0
  • Writing Secure Code – Second Edition
    Autores: Michael Howard e David LeBlanc
    Editora: Microsoft Press
    ISBN: 0-7356-1722-8
  • CLR via C# – Second Edition
    Autor: Jeffrey Richter
    Editora: Microsoft Press
    ISBN: 0-7356-2163-2
  • Programming Visual C# 2005: The Language
    Autor: Donis Marshall
    Editora Microsoft Press
    ISBN: 0-7356-2181-0
  • Expressões Regulares – Uma abordagem divertida
    Autor: Aurélio Marinho Jargas
    Editora: Novatec
    ISBN: 85-7522-100-0
  • Collection 5160: Core Development with Microsoft .NET Framework 2.0
    Autor/Editor: Microsoft
  • Collection 5161: Advanced Development with Microsoft .NET Framework 2.0
    Autor/Editor: Microsoft

Tags: , , , , , , , ,

.NET Framework | Async | C# | Security | VB.NET

Expondo coleções através de serviços

by Israel Aece 28. September 2007 09:05

Matevz Gacnik mostra aqui alguns pontos importantes para expor coleções através de métodos (serviços) utilizando WCF.

Tags: ,

CSD | WCF

Convertendo uma DataRow em um Objeto

by Israel Aece 27. May 2007 19:45

Em um projeto em qual estou trabalhando, precisei consumir um WebService e, para variar, ele retorna um Dataset e DataTables. Como em minha aplicação eu trabalho com objetos mais específicos, então tentei criar um método que convertesse cada uma das DataRows em um desses objetos e, para facilitar o trabalho, criei uma classe que é composta com alguns métodos estáticos e, entre eles, existe um que chamei de Converter:

public class CollectionHelper
{
    public static IEnumerable<TOutput> Converter<TInput, TOutput>(IEnumerable coll, Converter<TInput, TOutput> converter)
    {
        foreach (object o in coll)
        {
            yield return converter((TInput)o);
        }
    }
}

E para utilizá-lo:

IEnumerable<Usuario> result = CollectionHelper.Converter<DataRow, Usuario>(dt.Rows,
        new Converter<DataRow, Usuario>(delegate(DataRow dr)
{
    return new Usuario(dr["Nome"].ToString());
}));

Tags:

.NET Framework | Data

Explorando o LINQ

by Israel Aece 23. May 2007 19:48

Bem, não é uma tradição minha colocar aqui no blog os artigos que escrevo, mas como eu gostaria de um feedback maior e, sendo assim, vai aqui o link para o mesmo: http://www.israelaece.com/post/Explorando-o-LINQ-Background.aspx.

Como voces podem ver, eu estou publicando sob-demanda e, na medida em que eu for escrevendo eu estarei atualizando o artigo com as respectivas seções. Um detalhe importante para este artigo, é que antes de decidir escreve-lo, eu fiz uma enquete com algum dos meus alunos e grande parte deles disseram que o vídeo é muito interessante e, na opinião deles, até mais do que o próprio artigo. Apesar de não concordar muito com isso e lembrando que gosto de escrever, eu decidi criar os dois, ou seja, o artigo e o complemento dele que é um vídeo.

É importante dizer que críticas, dúvidas ou sugestões são sempre bem-vindas mas não vale reclamar da quantidade de "" e "ãhhhhhn" que tem no vídeo! :P

Tags: ,

.NET Framework | Data

System.Collections.Generic.HashSet

by Israel Aece 10. November 2006 09:03

Bem, felizmente o time da BCL (Base Class Library) trabalha em um tipo de coleção chamado (temporariamente) de HashSet, que é uma coleção de elementos únicos, ou seja, sem a possibilidade de incluir elementos repetidos. Essa coleção tem seu próprio método Add que retorna um valor booleano indicando se o item foi ou não adicionado.

Enquanto não temos disponível essa coleção, podemos optar pelo uso da PowerCollections.Set, criada pela Wintellect.

Tags:

.NET Framework

CollectionBase

by Israel Aece 14. August 2005 17:47

É muito comum em runtime retornarmos valores da Base de Dados e armazenarmos em DataSets, mas com isso ocorre o “Weakly Typed” e o “Late Binding”, ou seja, não temos a segurança de tipos e o acesso à suas propriedades somente ocorre durante o tempo de execução.

Tendo esse problema, o que podemos fazer para termos nossos próprios objetos com suas respectivas propriedades e métodos ao invés de uma genérica? Então neste artigo explicarei como podemos criar uma coleção customizada, onde utilizaremos o CollectionBase.

Esta classe é fornecida através do Namespace System.Collections, criada justamente para essa finalidade. Criaremos uma coleção de Usuários e colocaremos dentro de um controle ASP.NET DataList.

O CollectionBase é uma classe onde podemos apenas herdá-la. Ela implementa três interfaces: IList, ICollection e IEnumerable que definem os métodos que aceitam tipos de System.Object. Além disso, ela ainda encapsula um ArrayList, onde ficarão armazenados os elementos da coleção.

Vamos nos dedicar aos seguintes métodos: Add, Contains, Insert, Item e Remove. Explicando cada método:


Function Add
Retorno: Integer
Adiciona um novo Item na Coleção e retorna o indíce (posição) que o objeto foi adicionado.

Function Contains
Retorno: Boolean
Verifica se já existe um determinado objeto dentro da Coleção e retorna um valor boleano indicando ou não sua existência.

Sub Insert
Insere um Item na Coleção em uma determinada posição.

Property Item
Retorna ou Recebe um objeto dado uma posição.

Sub Remove
Remove um objeto da Coleção.

Sub RemoveAt
Remove um objeto da Coleção dado uma posição.


Como dito anteriormente, vamos então criar nossa coleção customizada. Primeiramente devemos criar a nossa classe Usuario onde conterá as suas respectivas propriedades. Para isso, criarei uma WebApplication para criarmos e utilizarmos nossa coleção de exemplo. Depois de criado a WebApplication no Visual Studio .NET, adicione um novo arquivo *.vb (Class) e nomeie para Usuario.vb. Nossa classe deverá ficar conforme a estrutura abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
Public Class Usuario
 
    Private _nome As String
    Private _email As String
 
    Public Property Nome() As String
        Get
            Return Me._nome
        End Get
        Set(ByVal Value As String)
            Me._nome = Value
        End Get
    End Property
 
    Public Property Email() As String
        Get
            Return Me._email
        End Get
        Set(ByVal Value As String)
            Me._email = Value
        End Get
    End Property
 
End Class
 
Código 1 - A Classe Usuário e suas propriedades.

Como podemos ver acima, criamos a Classe Usuario com as seguintes propriedades: Nome e Email. Agora devemos criar uma nova Classe chamada UsuarioColecao que será a nossa Coleção de Usuários. Para isso adicionarei mais um arquivo *.vb no projeto com o nome: UsuarioColecao.vb. Aqui devemos herdar o System.Collections.CollectionBase e devemos escrever os métodos e propriedades (Add, Contains, Insert, Item e Remove) para trabalharmos apenas com objetos do tipo Usuario, garantindo assim a "Segurança de Tipos". Veja o código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
29
29
30
 
Public Class UsuarioColecao
 
    Inherits System.Collections.CollectionBase
 
    Public Function Add(ByVal objUsuario As Usuario) As Integer
        Return MyBase.List.Add(objUsuario)
    End Function
 
    Public Function Contains(ByVal objUsuario As Usuario) As Boolean
        Return MyBase.List.Contains(objUsuario)
    End Function
 
    Public Sub Insert(ByVal index As Integer, ByVal objUsuario As Usuario)
        MyBase.List.Insert(index, objUsuario)
    End Sub
 
    Default Public Property Item(ByVal index As Integer) As Usuario
        Get
            Return CType(MyBase.List(index), Usuario)
        End Get
        Set(ByVal Value As Usuario)
            MyBase.List(index) = Value
        End Get
    End Property
 
    Public Sub Remove(ByVal objUsuario As Usuario)
        MyBase.List.Remove(objUsuario)
    End Sub
 
End Class
 
Código 2 - Coleção de Usuários.

Acima podemos ver na linha 3 que herdamos a System.Collections.CollectionBase na nossa classe UsuarioColecao. E para garantirmos a segurança de tipos da coleção, ou seja, para que todos os métodos trabalhem apenas com um determinado tipo de objeto (no nosso caso, Usuario), devemos especificar isso para cada método e propriedade. Para os fãs de coleções, uma das grandes inovações do Visual Studio .NET Whidbey serão as coleções genéricas (Generics). Para maiores informações sobre o Generics: http://download.microsoft.com/download/c/7/f/c7f7a575-79ac-4399-9535-3ed57bc292f2/generics.doc.

Bem, agora nossa Classe UsuarioColecao já está pronta para trabalhar/aceitar apenas objetos do tipo Usuario, criado anteriormente. Vamos então à um exemplo prático de como usá-las:

Figura 1 - Intellisense já reconhece as propriedades da nossa Classe Usuario.

Como podem ver na figura 1, criamos um objeto do tipo Usuario e na medida que vamos precisando dele, instanciamos o mesmo (usuario = New Usuario()). Depois de cada objeto criado e atribuído a eles seus respectivos valores, você deve adicioná-lo à coleção de Usuario, qual também já criamos e instanciamos no início do código. Abaixo o código completo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
Dim usuario As Usuario
Dim usuarioColecao As New UsuarioColecao()
 
usuario = New Usuario()
With usuario
    .Email = "israel@projetando.net"
    .Nome = "Israel Aéce"
End With
usuarioColecao.Add(usuario)
 
usuario = New Usuario()
With usuario
    .Email = "teste@servidor.net"
    .Nome = "José Augusto"
End With
usuarioColecao.Add(usuario)
 
Código 3 - Coleção de Usuários.


Figura 2 - Aceitando apenas objetos do tipo Usuario.

A figura 2 nos mostra algo bem interessante, pois reparem a o método Add qual utilizamos para adicionar um novo objeto Usuario em nossa coleção. Ele só aceita um objeto do tipo Usuario. Se tentarmos colocar uma String por exemplo, ele dará erro de compilação.

Como vimos, para todos os métodos (Add, Contains, Insert, Item e Remove) eles apenas irão trabalhar com objetos do tipo Usuario. Como disse no inicio do artigo, vou explicar como popular um controle DataList através de uma Coleção.

Logo após de criar e popular os objetos conforme o código 3, apenas devemos atribuir a Coleção à propriedade DataSource do DataList, e também colocar no HTML as propriedades que deseja exibir. O código abaixo carrega o controle DataList no evento Page_Load do WebForm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
Dim usuario As Usuario
Dim usuarioColecao As New UsuarioColecao()
 
usuario = New Usuario()
With usuario
    .Email = "israel@projetando.net"
    .Nome = "Israel Aéce"
End With
usuarioColecao.Add(usuario)
 
usuario = New Usuario()
With usuario
    .Email = "teste@servidor.net"
    .Nome = "José Augusto"
End With
usuarioColecao.Add(usuario)
 
With Me.dtlColecao
    .DataSource = usuarioColecao
    .DataBind()
End With
 
Código 4 - Carregando o controle DataList (Linha 18 à 21).

Ainda temos que colocar os campos que desejamos exibir no HTML. Para isso você deve utilizar as áreas ItemTemplate e AlternatingItemTemplate. No código abaixo estou exibindo as duas propriedades (Nome e Email) do objeto Usuario:

1
2
3
4
5
6
7
8
9
10
 
<asp:DataList...>
    <ItemTemplate>
        Nome: <%# DataBinder.Eval(Container.DataItem, "Nome")%><br>
        Email: <%# DataBinder.Eval(Container.DataItem, "Email")%>
    </ItemTemplate>
    <AlternatingItemTemplate>
        Nome: <%# DataBinder.Eval(Container.DataItem, "Nome")%><br>
        Email: <%# DataBinder.Eval(Container.DataItem, "Email")%>
    </AlternatingItemTemplate>
</asp:DataList>
 
Código 5 - Código HTML do DataList com as propriedades do objeto Usuario.

Como podem ver abaixo, o controle DataList carregado com os dados e exibindo as propriedades do objeto Usuario:

Figura 3 - DataList já carregado.

E quando utilizamos DataGrid não há problemas com relação à paginação como acontece com o DataReader. E também quando for definir as colunas de um DataGrid, ao invés de no campo Data Field do Property Builder, você informar o nome do campo da Base de Dados, você apenas atribui à ele o nome da propriedade que deseja exibir.

E ainda você pode optar por escrever os itens da coleção. Para isso basta executar um laço For...Next e percorrer a coleção e escrever os seus itens. O código abaixo explica como fazer isso:

1
2
3
4
5
 
Dim i As Integer
For i = 0 To usuarioColecao.Count - 1
    Response.Write("Nome: " & usuarioColecao.Item(i).Nome & "<br>")
    Response.Write("Email: " & usuarioColecao.Item(i).Email & "<br><br>")
Next
 
Código 6 - Percorrendo e escrevendo os itens da Coleção.

E o resultado ficará algo como:

Figura 4 - Escrevendo os Itens da Coleção.

Conclusão: Neste artigo vimos como é simples construirmos Coleções customizadas derivadas do System.Collections.CollectionBase. Apesar de que para cada objeto, temos que ter uma Coleção específica, onde temos que reescrever cada método para que aceite um determinado objeto. Mas com o Generics as coisas ficaram mais fáceis, mas de qualquer forma, vimos a facilidade de escrever Coleções customizadas e atribuirmos à um controle.

Tags:

.NET Framework

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