[Collection].RemoveAt(index)

Hoje recebi um email de um colega que me solicitava uma ajuda com relação ao controle CheckBoxList, onde ele tem um CheckBoxList no seu WebForm que carrega com alguns items. No evento Click de um Button qualquer, ele deveria excluir os items que foram marcados do CheckBoxList.

Pois bem, ele me mostrou o código que ele estava utilizando para isso, no evento Click de um Button:

        For i As Integer = 0 To Me.CheckBoxList1.Items.Count – 1
            If Me.CheckBoxList1.Items.Item(i).Selected Then
                Me.CheckBoxList1.Items.RemoveAt(i)
            End If
        Next

Mas isso atira uma Exception, do tipo: “Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index” caso você marque um item do CheckBoxList que não seja o último, e tem mesmo que ser apenas um, o que perde um pouco o sentido, já que a idéia de utilizar um CheckBoxList é permitir a múltipla escolha.

E se analisarmos o código que conseguimos ao fazer o disassembler, através do Reflector, da propriedade Items do CheckBoxList (que internamente é retornado um ListItemCollection (que encapsula um ArrayList)), mais precisamente do método RemoveAt, temos o seguinte código:

        Public Overridable Sub RemoveAt(ByVal index As Integer)
                If ((index < 0) OrElse (index >= Me._size)) Then
                        Throw New ArgumentOutOfRangeException(“index”, Environment.GetResourceString(“ArgumentOutOfRange_Index”))
                End If
                Me._size -= 1
                If (index < Me._size) Then
                        Array.Copy(Me._items, CType((index + 1), Integer), Me._items, index, CType((Me._size – index), Integer))
                End If
                Me._items(Me._size) = Nothing
                Me._version += 1
        End Sub

Como vemos, ele remove o elemento especificado no index e reconstrói o Array, através do método Array.Copy(…). Mas a Exception não “explode” ai e sim, quando a próxima iteração do laço For … Next for chamada, quando tentamos resgatar o próximo Item do ArrayList, item qual já não existirá mais, e vemos exatamente neste método a Exception que é atirada:

        Public Overridable Function get_Item(ByVal index As Integer) As Object
                If ((index < 0) OrElse (index >= Me._size)) Then
                Throw New ArgumentOutOfRangeException(“index”, Environment.GetResourceString(“ArgumentOutOfRange_Index”))
                End If
                Return Me._items(index)
        End Function

Mas e como fazemos para resolver este problema? Pois bem, a solução é lá bem simples, bastando apenas mudar a ordem do laço For … Next, ou seja, ao invés de percorrer a coleção de items do CheckBoxList de 0 até o número total de Items (ascendente), faz ao contrário, descrecendo (em 1) do número total de Items até 0. Ajustando o código acima (aquele da exclusão de items), fica conforme o código mostrado baixo:

        For i As Integer = Me.CheckBoxList1.Items.Count – 1 To 0 Step -1
            If Me.CheckBoxList1.Items.Item(i).Selected Then
                Me.CheckBoxList1.Items.RemoveAt(i)
            End If
        Next

Agora, o index nunca vai ser maior ou igual ao tamanho do ArrayList. Vale lembrar que isso não é válido somente para o CheckBoxList, mas sim todas as classes que implementam a interface IList.

AppDomain

Esses dias estava perguntando ao João uma boa definição do que é um AppDomain. E ele me disse que não tem como sabermos o que é um Domínio de Aplicação se não soubermos o que é um Processo. Pois bem, dando uma olhada eu alguns materiais que tenho aqui, encontrei definições para estes:

[ AppDomain ]
Um domínio de aplicação (freqüentemente AppDomain) é um processo virtual que serve para isolar uma aplicação. Todos os objetos criados no mesmo escopo de aplicação (em outras palavras, em qualquer lugar junto à seqüência de ativações de objeto iniciando com o ponto de entrada de aplicação) são criados no mesmo domínio de aplicação. Múltiplos domínios de aplicação podem existir em um único processo do sistema operacional, tornando-os um meio leve de isolamento de aplicação.

[ Processo ]
Um processo de SO proporciona isolamento tendo um espaço de endereçamento de memória distinto. Embora isto seja efetivo, também é caro e não pode ser escalado para os números necessários para grandes servidores web. O Common Language Runtime, por outro lado, reforça o isolamento de aplicação gerenciando o uso de memória do código rodando no domínio de aplicação. Isto garante que o código não acessa memória fora dos limites do domínio. É importante notar que somente código type-safe pode ser gerenciado dessa forma (o runtime não pode garantir isolamento quando código não seguro é carregado em um domínio de aplicação).

Lendo Arquivos a partir de uma URL

Esse post até é de certa forma engraçado. Estava navegando pelo fórum, e havia um rapaz precisando com certa urgencia ler arquivos que estavam em outro computador. Bem logo pensei, vou ver se encontro algo para ajudá-lo. Abri o Help do Visual Studio .NET e procurei pela classe HttpWebRequest, e me baseando no exemplo e com o auxilio do StreamReader fiz com que esse código pegue o conteúdo de um arquivo, fornecendo a URL do mesmo e escreva seu contéudo na tela. Abaixo o código:

Dim webreq As HttpWebRequest = CType(WebRequest.Create(“http://localhost/DropListTest/Teste.txt“), HttpWebRequest)
Dim webresp As HttpWebResponse = CType(webreq.GetResponse(), HttpWebResponse)
Dim strm As New StreamReader(webresp.GetResponseStream(), Encoding.Default)
Dim sLine As String
Do
        sLine = strm.ReadLine()
        Response.Write(sLine & “<br>”)
Loop While Not (sLine Is Nothing)
strm.Close()

Bem, depois do código funcionando, fui responder à duvida dele, pois quando prestei atenção no post, ele queria resgatar o valor desse arquivo através de um caminho fisico, exemplo: \serverpastaarquivo.txt. É isso que dá não ler as coisas com atenção. Mas valeu, pois eu não sabia utilizar a classe HttpWebRequest. 😉

Invocando Métodos

Estou lendo um livro chamado Writing Secure Code, e na seção onde aborda como escrever código .NET seguro, o autor usa uma forma de chamar métodos da instância de uma determinada classe de uma forma que eu ainda não conhecia. Achei mesmo muito interessante. Abaixo o exemplo:

          public class InstanceTest{
                    public void Show(string p){
                              MessageBox.Show(p);
                    }
          }

Acima uma classe simples com um método. Como disse, o interessante é a forma com qual o método é invocado:

          private void Form1_Load(…){
                    new InstanceTest().Show(“Test”);
          }

Como podemos ver, logo após instanciarmos a classe, já conseguimos acessar os métodos de instância deste objeto. Tenho que confessar que isso é uma novidade para mim. Fui tentar fazer o mesmo no Visual Basic .NET, mas não resultou. 😦

.NET vs. JAVA

Estou acompanhando uma daquelas intermináveis discussões sobre a Plataforma .NET vs. JAVA em um determinada lista de desenvolvimento de software. Achei muito interessante a citação de um dos integrantes do grupo que em sua opinião sobre a “briga”, onde ele disse:

“De minha parte, entre Java e .NET, fico com arquitetura de software, MDA e Governança de TI. Na guerra entre as partes, prefiro vender a munição. E aproveitem, que está com desconto!!!”.

Legal 🙂

Comparação de Strings

Como sabemos, o .NET Framework nos fornece várias formas de compararmos Strings. Pois bem, isso me deixou bastante curioso, visto que com estas opções, saber qual é a mais rápida. Não sei se o teste de performance que criei é lá o ideal, mas deu para ter uma idéia.

O teste consiste em um laço For … Next de 0 até 1.000.000.000, onde dentro do laço eu utilizo as comparações de Strings. O teste foi realizado para quando as Strings são iguais e também quando são diferentes, e o resultado é interessante por causa que dependendo se as Strings forem iguais uma forma é mais rápida, ao contrário de elas forem diferentes, ou seja, um outro método é mais eficaz. Vamos então ver a estrutura do código que escrevi para o teste/comparação:

        Dim d1 As DateTime
        Dim d2 As DateTime
        Dim t As TimeSpan
        Dim s1 As String = “valor1”
        Dim s2 As String = “valor1”

        GC.Collect()

        d1 = DateTime.Now
        For i As Integer = 0 To 1000000000
                ‘Aqui a comparação (abaixo)
        Next
        d2 = DateTime.Now
        t = d2.Subtract(d1)
        Console.WriteLine(t.ToString())

Pois bem, com esta mesma estrutura utilizei as tres formas de comparação de Strings para testá-las. As condicionais são:

            [ Forma 1 ]
                        If String.Equals(s1, s2) Then
                        End If

            [ Forma 2 ]
                        If s1 = s2 Then
                        End If

            [ Forma 3 ]
                        If s1.Equals(s2) Then
                        End If

Os testes foram feitos para quando as Strings (s1, s2) foram iguais quanto diferentes. Para ser sincero, eu imaginei que poderia haver alguma diferença, mas que seria algo mínimo, questões de milisegundos, mas depois do teste, vi que se elas forem iguais, o custo é um pouco maior para alguns dos casos. Abaixo os resultados que obtive:

            [ Strings Iguais ]
                        Forma 1 – 00:00:07.7962762
                        Forma 2 – 00:00:35.2941642
                        Forma 3 – 00:00:25.6074082

            [ Strings Diferentes ]
                        Forma 1 – 00:00:28.8443038
                        Forma 2 – 00:00:30.4536014
                        Forma 3 – 00:00:24.3753120

Os testes foram feitos em um PC com a seguinte configuração: P4, 3Ghz, 512RAM, e monitor LCD 😛

Bem, fica aí os testes. Ainda não consegui identificar o porque um é mais rápido que o outro. Se alguém souber, e quiser compartilhar, fique a vontade.

Service is running

Há aproximadamente dois meses iniciei um projeto onde tive que construir um Windows Service (ou WinService). Pois bem, a finalidade do mesmo é resgatar os registros de uma determinada Base de Dados e enviar para um orgão chamado SERASA.

Este orgão tem a finalidade de fornecer informações sobre créditos e restrições financeiras, entre outros documentos e serviços, relacionados à pessoas físicas ou jurídicas (Empresas). Eles fornecem várias formas de resgatar do cliente e devolver para o mesmo tais informações. Alguns dos meios são Sockets, HTTPs e algo que não estou recordando agora (uma solução da IBM).

Como a idéia era criar tudo em .NET, fomos logo lá entender o problema. Ao cadastrar os Clientes na Base de Dados de um sistema interno (desenvolvido em Delphi), o serviço deverá correr sem nenhuma intervenção humana (claro, é esta a finalidade de um WinService) e automaticamente gerar a String de envio e receber o valor de retorno do SERASA. Vale lembrar que muitas vezes, o retorno não é imediato, tendo assim que ficar de tempo em tempo enviando uma String para checar se o lote que foi enviado já foi ou não processado.

Para que o processo corresse corretamente, tivemos que nos atentar à algumas condições, pois existiam seis tipos de documentos a serem enviados e recebidos. O processo de resgate dos dados da Base de Dados, a geração da String de envio, o recebimento e análise do retorno e a persistência na DB são iguais para todos, ou seja, os passos a serem executados devem ser exatamente os mesmos. A solução neste caso, foi criar uma classe Base que implementa um Template Method e dentro dele define os passos do algoritmo, deixando as subclasses (as classes derivadas) implementarem os métodos como eles devem ser, ou seja, é exclusivo para cada subclasse, pois a geração da String de envio por exemplo é diferente entre os tipos de documentos a serem enviados.

Bem, depois do envio e recebimento OK, vem a parte da persistência dos dados retornados pelo SERASA na Base de Dados. Neste caso, tenho cerca de 23 tabelas com média 15 à 30 campos em cada uma delas. Como tenho os meus objetos na minha aplicação e não queria criar uma DAL/DAO para resgatar os dados e assim popular cada um dos meus objetos, e estes por sua vez adicionar à coleção adotamos o NHibernate (ferramenta de OR/M), e com isso, diminuiu à 0 (Zero) a escrita de códigos T-SQL e Stored Procedures.

Por fim, é criado as Threads que são necessários para que essas “rotinas” corram “side-by-side”, e assim aumentando a facilidade e produtividade interna da empresa que está a utilizar este WinService.

IsDate()?

Bem, isto já é uma curiosidade que tenho há tempos: As linguagens de programação tem funções para que seja possível validar uma data. Uma famosa, qual acredito que muitos de voces conhecem, é a função IsDate(expression) do Visual Basic. Bem, como vemos, dado uma expressão ela nos retorna um valor booleano indicando se a data é ou não válida.

Com funções deste tipo (independente da linguagem de programação utilizada), seria completamente absurdo criamos aquelas funções gigantescas, onde “splitamos” a string que contém a data, e analisamos os valores separadamente, por exemplo:

If [dia] > 30 Then
If [mes] > 12 Then

Agora a tal dúvida: será que lá em baixo (digo, baixo nível) quando chamamos os métodos de validação de data, como o IsDate() ou qualquer outra função de validação de datas, não é feito algo dessa forma para validar se uma data é ou não válida? Será que alguém consegue imaginar o que é feito internamente?

O/R Mapping – NHibernate – Resource Files

Bem, a batalha para implementar o NHibernate continua. Precisei há pouco persistir o estado dos meus objetos nas 21 tabelas da DB (SQL Server 2000). Utilizando o NHibernate, o que tive a fazer foi somente criar os arquivos de mappings (a parte mais chata, mas nada muito complicado) e também definir o arquivo de configuração do NHibernate mapeando os arquivos de resources (conforme figura abaixo), quais optei por faze-los em “Embedded Resources”.

Feito isso, é agora somente chamar o método Save(…) e passar o objeto à persistir e tudo magicamente aparece nas devidas tabelas da DB sem escrever uma query SQL, definir parametros, definir e gerir conexões, etc.

Se não estiver a utilizar “Embedded Resources” pode ao invés de fazer o mapping para o Resource, faz-se o mapping diretamente para o arquivo XML.

Bem, aos poucos vou colocando por aqui as novidades sobre este O/RM.

Lendo Arquivos TXT com DataReader

Uma forma rápida de ler arquivos textos sem utilizar as classes contidas no Namespace System.IO e manipular linha a linha do conteúdo do arquivo texto, é utilizando Odbc, que através do mesmo vocè informa na ConnectionString o path do arquivo texto. Na Query faz o SELECT apontando a cláusula FROM para a tua fonte, que no caso é o nome do arquivo.

Definido esses passos, agora pode tratar normalmente como se estivesse utilizando uma Base de Dados Relacional. Exemplo para popular os dados de um DataGrid com os dados vindos do arquivo texto que contém os seguintes dados:

[ Conteúdo do Arquivo.txt ]

Categoria, Codigo
ASP.NET, 1
VB.NET, 2
C#, 3

[ Código ]

Imports System.Data.Odbc
Dim cnn As New OdbcConnection(“Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=C:”)
Dim cmd As New OdbcCommand(“SELECT * FROM Arquivo.txt”, cnn)
Dim dr As OdbcDataReader
Try
    cnn.Open()
    dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    With Me.DataGrid1
        .DataSource = dr
        .DataBind()
    End With
Catch ex As Exception
    Response.Write(“Ocorreu um erro.”)
Finally
    If Not (dr Is Nothing) Then dr.Close()
End Try

Reparem que a primeira linha do conteúdo do “Arquio.txt” torna-se o nome das colunas dos “registros”, qual neste caso, rotula os Headers das colunas do DataGrid. Vale chamar a atenção que o delimitador é a vírgula (“,”).