C# Tips & Tricks - Métodos ForEach

É comum criarmos loops for each em nosso código para realizarmos uma determinada ação nos items de uma lista ou array. Alguns desenvolvedores não sabem que desde a versão 2.0 do .NET Framework existem métodos que simplificam bastante essa abordagem.

Vamos criar uma classe simples para utilizarmos posteriormente no código.

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1}\nEmail: {2}", FirstName, LastName, EmailAddress);
    }
}

Essa classe representa um cliente que possui um nome, sobrenome e e-mail. Além disso, sobrescreve o método ToString de System.Object e utiliza propriedades automáticas (C# 3.0).

Vamos agora criar uma lista genérica de clientes.

var lista = new List<Customer>
{
    new Customer { FirstName = "Ari", LastName = "Raimundo", EmailAddress = "ari@mail.com"},
    new Customer { FirstName = "Anders", LastName = "Hejlsberg", EmailAddress = "anders@mail.com"},
    new Customer { FirstName = "Bill", LastName = "Gates", EmailAddress = "bill@mail.com"},
    new Customer { FirstName = "Jesse", LastName = "Liberty", EmailAddress = "jesse@mail.com"}
};

Digamos que queremos alterar o sobrenome de todos os clientes para letras maiúsculas. O código abaixo seria o caminho mais comum.

foreach (var c in lista)
    c.LastName = c.LastName.ToUpper();

O que poucos conhecem é que a classe List possui o seguinte método.

public void ForEach(Action<T> action);

O método ForEach realiza a ação especificada pelo parâmetro action em todos os itens da lista. O parâmetro action é do tipo System.Action<T>, ou seja, encapsula um método que não retorna valor e possui um parâmetro que é o item da lista.

Podemos substituir o loop então da seguinte forma:

lista.ForEach(c => { c.LastName = c.LastName.ToUpper(); });

Estou usando uma expressão lambda para representar o parâmetro action. O range dessa expressão seria a variável c, que é do tipo Customer.

Vamos modificar o código um pouco para mostrar os clientes na tela de console.

lista.ForEach(c =>
{
    c.LastName = c.LastName.ToUpper();
    Console.WriteLine(c);
});

Simples não é? Agora vamos fazer o mesmo com o array do código abaixo.

var array = new Customer[]
{
    new Customer { FirstName = "Ari", LastName = "Raimundo", EmailAddress = "ari@mail.com"},
    new Customer { FirstName = "Anders", LastName = "Hejlsberg", EmailAddress = "anders@mail.com"},
    new Customer { FirstName = "Bill", LastName = "Gates", EmailAddress = "bill@mail.com"},
    new Customer { FirstName = "Jesse", LastName = "Liberty", EmailAddress = "jesse@mail.com"}
};

A diferença agora é que iremos utilizar um método estático da classe System.Array. Esse método tem dois parâmetros: o array e a ação a ser executada em seus itens.

public static void ForEach<T>(T[] array, Action<T> action);

Para fazer o loop e mostrarmos os clientes na tela de console utilizamos o código abaixo.

Array.ForEach(array, c =>
{
    c.LastName = c.LastName.ToUpper();
    Console.WriteLine(c);
});

Bom, você deve estar se perguntando: qual a diferença? Existe diferença de performance? Bom, não fiz nenhum teste, vejam o link abaixo e tirem suas próprias conclusões.

Performance of foreach vs. List.ForEach
http://bit.ly/5VKDrD

Particularmente, sugiro que utilizem esses métodos.

Um método pode retornar um tipo anônimo?

Os tipos anônimos (Anonymous Types) são uma característica da linguagem C# onde criamos diversas propriedades para um objeto sem ter que definir explicitamente seu tipo. Essa novidade surgiu na versão 3.0 junto com diversas outras tais como: propriedades automáticas, inferência de tipos, inicializadores de objetos, expressões lambda, métodos de extensão e outros.

Um tipo anônimo pode ser declarado da seguinte maneira:

var c = new { Nome = "Ari", Idade = 28 };

Neste caso a variável c é um tipo de possui duas propriedades: uma propriedade do tipo System.String chamada Nome e uma propriedade do tipo System.Int32 chamada Idade.

Os tipos anônimos são muito úteis quando realizamos consultas usando o LINQ pois normalmente temos que retornar um tipo com um conjunto de propriedades diferente dos tipos já existentes. Por exemplo, vejam as duas consultas abaixo:

var q1 = from c in dc.Customers
         where c.City == "London"
         select new { c.FirstName, c.LastName, c.City };

var q2 = from c in dc.Customers
         where c.City == "London"
         select new { c.FirstName, c.City };

A primeira consulta retorna um tipo que contém 3 propriedades (FirstName, LastName e City) e a segunda um tipo com 2 propriedades (FirstName e City). Sem os tipos anônimos teríamos que definir explicitamente duas classes para representar os tipos retornados.

Mas, se o tipo é anônimo, como podemos fazer para um método retorná-lo?

public ???? ListCustomers()
{
    var q1 = from c in dc.Customers
             where c.City == "London"
             select new { c.FirstName, c.LastName, c.City };

    return q1;
}

Bom, podemos resolver essa questão pensando da seguinte maneira: se um tipo anônimo é um tipo do .NET, então esse herda de System.Object, vamos então retornar um object.

public object ListCustomers() { ... }

Esse raciocínio está correto, o problema é que transformando para object perdemos a possibilidade de utilizarmos as propriedades do tipo anônimo diretamente (strong typing).

var c = ListCustomers();
c.FirstName = "Anders"; // erro

Bom, para resolver esse problema temos 3 possíveis soluções:

  1. Reflection.
  2. Dynamic Programming.
  3. Realizar um cast do object com o tipo anônimo.

A primeira opção é lenta e muito código deve ser criado, portanto será descartada. A segunda opção é interessante mas vou limitar meu escopo com as versões anteriores à 4.0. Vou mostrar então a terceira opção.

Para realizarmos um cast de um object para um tipo anônimo podemos, com auxílio de Generics, criar o método abaixo:

public T CastObjectToType<T>(object objeto, T tipo)
{
    return (T)objeto;
}

Podemos então converter o objeto em um tipo anônimo da seguinte maneira:

object o = ListCustomers();
var c = CastObjectToType(o, new { FirstName = String.Empty, 
                                  LastName = String.Empty, 
                                  City = String.Empty});
c.FirstName = "Anders";  // OK

Isso é possível graças à inferência de tipo, que nos permite fazer um cast sem conhecer o nome do tipo. É o que foi realizado no método CastObjectToType.

Finalizado, a resposta é SIM. Podemos retornar um tipo anônimo de um método.

Links de ajuda:

Anonymous Types (C# Programming Guide)
http://bit.ly/69HYJd

Generic Methods (C# Programming Guide)
http://bit.ly/6wFbas

Getting Started with LINQ in C#
http://bit.ly/4BOIUU

Option Strict e ByRef

Todo mundo já sabe que o VB.NET não é uma linguagem fortemente tipada (strongly typed) tal como C, C++ ou C#. Mas o que é uma linguagem fortemente tipada? Ser fortemente tipada indica que cada variável possui um tipo definido em tempo de compilação.

Em VB.NET podemos realizar conversões de dois tipos: widening e narrowing. Para exemplificar melhor digamos que temos as duas variáveis abaixo.

Dim var1 As System.Int32
Dim var2 As System.Int16

A conversão widening muda o valor de um tipo que pode acomodar qualquer possível valor do tipo original. Por exemplo, o tipo System.Int32 contém toda a faixa de valores do tipo System.Int16.

' conversão widening
var1 = var2

A conversão narrowing muda o valor de um tipo que pode não estar apto a armazenar alguns possíveis valores do tipo original. Por exemplo, o tipo System.Int16 contém uma parte dos valores do tipo System.Int32.

' conversão narrowing
var2 = var1

Em VB.NET existe uma opção chamada Option Strict que, quando ligada, restringe conversões implícitas de tipos para somente conversões do tipo widening. O uso dessa opção é extremamente recomendada, já que temos as seguintes vantagens:

  • Checagem do tipo em tempo de compilação (strong typing).
  • Previne perda de dados em conversões.
  • Não permite late-binding, ou seja, não permite que as conversões sejam checadas em tempo de execução.
  • Melhora a performance porque o tipo é explícito e de certa forma não precisa ser “adivinhado”.

O engraçado dessa história é que a opção vem desabilitada por padrão. É possível habilitá-la pelo código, pela IDE do Visual Studio ou alterando uma opção pelo compilador.

Para habilitar a opção pelo código temos que incluir o seguinte trecho no início do código-fonte antes de qualquer outro código.

Option Strict On

Para definir a opção pela IDE do Visual Studio temos que seguir os seguintes passos.

  1. No menu Tools, clique em Options.
  2. Vá até o nó Projects and Solutions.
  3. Escolha VBDefaults.
  4. Modifique a configuração do Option Strict.

Para definir no compilador a opção /optionstrict deve ser adicionada à linha de comando.

Bom, vamos chegamos agora ao ponto principal do post que é mostrar o comportamento dessa opção em um caso específico. Digamos que temos o seguinte método abaixo:

Public Sub MetodoX(ByRef obj As Object)
...
End Sub 

Considerando que qualquer tipo no .NET herda de System.Object podemos passar então qualquer tipo de variável para esse método. Correto?

NÃO se a opção Option Strict estiver ligada. Por quê?

Quando passamos o um argumento ByRef para um método este pode alterar o valor do parâmetro. Como o parâmetro do exemplo é um tipo System.Object, dentro do método a variável obj pode ser convertida para qualquer outro tipo, inclusive um tipo cuja conversão seja do tipo narrowing.

Explicando melhor, se passarmos por exemplo um valor do tipo System.Int32 para o método e dentro deste a variável obj é convertida para System.Int64, como o parâmetro é ByRef, uma conversão narrowing será realizada (tentativa de transformar System.Int32 em System.Int64). O código gera o seguinte erro: Option Strict On disallows implicit conversions.

Dim param1 As System.Int16

' chamada do método
MetodoX(param1)

' quem garante que após a chamada do método o parâmetro continua sendo System.Int16?

Se parâmetro obj do método for modificado para ByVal, o erro desaparece porque não temos mais a conversão narrowing.

Esse foi uma questão interessante de um colega dos fóruns do MSDN.

Links de ajuda:

Option Strict Statement
http://bit.ly/8Fl9oj

Option Strict On disallows narrowing from type '' to type '' in copying the value of ByRef parameter ' back to the matching argument
http://bit.ly/6V4Bf8

Widening and Narrowing Conversions
http://bit.ly/8GiNBW

Asynchronous Method Invocation usando Delegates

Seguindo a sugestão do meu amigo Diego Azevedo vou demonstrar neste post como fazer a chamada de um método de forma assíncrona utilizando um padrão conhecido como Asynchronous Method Invocation (AMI).

Vou limitar o escopo desse post a um método de uma classe que possui somente um parâmetro e que retorna um valor.

Na maioria das linguagens de programação por padrão um método é executado de forma síncrona, ou seja, quando chamamos o método este é executado e somente quando termina é que a linha de execução do programa continua.

Por exemplo, no código abaixo a mensagem "Terminei !" só é mostrada quando o método FacaAlgumaCoisa é finalizado.

Classe objeto = new Classe();
objeto.FacaAlgumaCoisa();
Console.WriteLine("Terminei !")

Digamos que NÃO queremos que o usuário aguarde que o método FacaAlgumaCoisa termine para continuar a execução do programa. Queremos então estar aptos a utilizar o programa e fazer outras operações enquanto o método é executado. Temos então que desenvolver uma aplicação que seja multi-tarefa ou multi-threading em inglês.

Não quero entrar muito a fundo no conceito de multi-threading e deixo esse estudo como "dever de casa".

O código abaixo será uma aplicação console C# em Visual Studio 2008 Professional SP1 usando o .NET 3.5. É possível também utilizarmos a versão Express sem problemas.

Vamos começar criando uma classe qualquer que iremos utilizar em nosso exemplo. Para simplificar, vamos criar a classe no arquivo Program.cs mesmo.

public class MinhaClasse
{
    // exemplo de método que demora em torno de 10 segundos
    // para ser executado e retorna um valor
    public int MetodoDemorado(int a)
    {
        System.Threading.Thread.Sleep(10000);
        return a + 10;
    }
}

A classe é bem simples e contém um método que possui um parâmetro do tipo int e retorna o resultado da soma deste com o valor 10. O método estático Sleep da classe Thread foi introduzido no exemplo somente para simular um processamento que leva em torno de 10 segundos para executar.

Vamos declarar então no método Main um objeto da classe MinhaClasse.

// cria instância da classe MinhaClasse
MinhaClasse objeto = new MinhaClasse();

A idéia deste post é executar o método MetodoDemorado de forma assíncrona. Para executar um método de forma assíncrona precisamos de um delegate. Delegate é um tipo que referencia um método, similar aos ponteiros para funções do C/C++ (você já deveria saber disso !).

Felizmente no .NET 3.5 temos, com ajuda de Generics, alguns delegates que encapsulam alguns métodos. Neste exemplo vou utilizar o delegate System.Func pois preciso de um delegate que receba um inteiro e retorne um inteiro.

Criamos então a instância do delegate passando o método MetodoDemorado como parâmetro, conforme o código abaixo.


// encapsula o método em um delegate
Func<int, int> async = new Func<int, int>(objeto.MetodoDemorado);

Obs: Se o método não retornasse valor poderíamos utilizar o delegate System.Action.

Para executar o método de forma assíncrona vamos utilizar o método do delegate BeginInvoke gerado pelo compilador. Teremos que passar então como argumentos um inteiro, que é o parâmetro do método MetodoDemorado, um método callBack chamado quando o método finalizar a execução e um objeto que representa um estado qualquer.

async.BeginInvoke(...);

O argumento para o método callBack é uma expressão lambda que representa um delegate anônimo, ou seja, um delegate que recebe um parâmetro IAsyncResult e não retorna valor. No código acima, r é o parâmetro IAsyncResult. Além disso, estamos passando o valor 10 como argumento do método MetodoDemorado e null para o estado.

async.BeginInvoke(10, (r) =>
{
... // aqui é o corpo do callBack
}, null);

Utilizamos o método EndInvoke do delegate async para pegar o valor retornado pelo método MetodoDemorado. Após a execução do método, mostramos uma mensagem com o resultado.

// executa o método de forma assíncrona
async.BeginInvoke(10, (r) =>
{
    // resultado do método
    int resultado = async.EndInvoke(r);
    
    // mostra resultado
    Console.WriteLine("Resultado: {0}", resultado);

}, null);

Vamos incluir após o método BeginInvoke uma mensagem para que a aplicação console não seja finalizada e também vamos utilizar o método ReadKey que irá aguardar com que o usuário clique em uma tecla para finalizar a aplicação.

Segue abaixo portanto o código completo.

using System;

namespace MetodoAssincrono
{
    public class MinhaClasse
    {
        // exemplo de método que demora em torno de 10 segundos
        // para ser executado e retorna um valor
        public int MetodoDemorado(int a)
        {
            System.Threading.Thread.Sleep(10000);
            return a + 10;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // cria instância da classe MinhaClasse
            MinhaClasse objeto = new MinhaClasse();

            // encapsula o método em um delegate
            Func<int, int> async = new Func<int, int>(objeto.MetodoDemorado);

            // executa o método de forma assíncrona
            async.BeginInvoke(10, (r) =>
            {
                // resultado do método
                int resultado = async.EndInvoke(r);
                
                // mostra resultado
                Console.WriteLine("Resultado: {0}", resultado);

            }, null);

            Console.WriteLine("Aguardando execução do método...");
            Console.ReadKey(true);
        }
    }
}

Se executarmos essa aplicação, na tela de prompt será informado...



Só aqui já podemos perceber que a execução do método foi assíncrona, visto que a mensagem encontra-se após o BeginInvoke. Se aguardarmos um pouco (+- 10 segundos) poderemos ver a mensagem de retorno do método MetodoDemorado.



Espero ter sido claro e conseguido compartilhar com vocês esse tipo de técnica. Vou criar futuramente um post semelhante em uma aplicação Windows Forms tratando operações cross-thread.

Segue abaixo alguns links interessantes:

Delegate (C# Programming Guide)
http://bit.ly/54QbSD

Lambda Expressions (C# Programming Guide)
http://bit.ly/87xAZJ

Anonymous Delegates (C# Programming Guide)
http://bit.ly/6jZdYS

Func Delegate
http://bit.ly/5nAva4

Asynchronous Programming Using Delegates
http://bit.ly/6tcwzD

Must-Watch Videos – Anders Hejlsberg

Todo mundo já ouviu falar de role-model? É uma pessoa que serve de exemplo de comportamento. No mundo profissional, o meu role-model é Anders Hejlsberg.

anders Anders Hejlsberg (nome complicado de pronunciar e escrever) é Microsoft Technical Fellow e criador de ferramentas de desenvolvimento e linguagens de programação. Ele é também chief designer da linguagem C# e um dos principais participantes no desenvolvimento do .NET Framework.

Antes de trabalhar com C# e com o .NET Framework, Hejsberg foi o arquiteto de desenvolvimento do Visual J++ e do Windows Foundation Classes.

Hejlsberg foi um dos primeiros empregados da Borland e foi o autor original do Turbo Pascal, uma IDE revolucionária (era muito bom) e também chief architect do Delphi.

Na minha opinião, os feitos desse gênio modificaram a maneira com que trabalhamos com Frameworks e linguagens de programação.

Vou enumerar abaixo alguns dos vídeos que acredito serem obrigatórios para conhecer essa “figura”.  Os vídeos, além de mostrar a geniosidade de Anders, também é muito útil para entender conceitos sobre Generics, LINQ e Dynamic Programming.

1 - MSDN TV: Whiteboard with Anders Hejlsberg

No evento Tech-Ed de 2004 Anders responde as questões de alguns desenvolvedores e escreve alguns exemplos em um quadro. É interessante perceber a qualidade das perguntas e a maneira simples com que Hejlsberg as responde. Diversos assuntos são comentados, incluindo: generics, herança múltipla, parâmetros opcionais e outros.

É interessante perceber que na época ele não achava que os parâmetros opcionais, agora presentes no C# 4.0, seriam necessários, visto que podemos sobrecarregar métodos.

Link: http://bit.ly/4Z2qLe (Tamanho: 153MB)

2 – Channel 9: LINQ

Em um papo descontraído Anders fala sobre o LINQ, que é um conjunto de extensões para o .NET Framework que engloba operações de consulta, projeção e transformação integradas às linguagens. O LINQ foi uma inovação e tanto e também alterou a maneira de escrevermos código que realizam acesso a dados.

Data != Objects ? Com LINQ não !

Link: http://bit.ly/4AwCTg (Streaming)

3 – MSDN Spotlight: .NET Language Integrated Query (LINQ) Framework Overview

Esse vídeo é uma apresentação no Tech-Ed de 2007 e apesar de possuir alguns assuntos semelhantes ao vídeo #2 contém também explicações sobre o LINQ Framework, que inclui: LINQ to Objects, LINQ to Datasets, LINQ to SQL, LINQ to Entities e LINQ to XML.

Alguns demos sobre LINQ to Objects, LINQ to SQL e LINQ to XML são demonstrados. Vale a pena conferir.

Link: http://bit.ly/5sCNIe (Streaming)

4 – Channel 9: Future of C#

Esse é um dos meus vídeos favoritos e é uma apresentação no PDC de 2008 e que mostra a inclusão de Dynamic Programming no C#, parâmetros opcionais, compilador como um serviço e também a idéia de co-evolução entre as linguagens C# e VB.NET.

Link: http://bit.ly/6Tqq2k (Streaming)

Obs: No PDC de 2009 o Luca Bolognesi, responsável pelas linguagens C#, VB.NET e F# fez uma apresentação basicamente mostrando os mesmo assuntos. É um outro vídeo bem interessante.

Link: http://bit.ly/6FSA1X (Streaming)

Espero que gostem.

C# Tips & Tricks - StringBuilder

Esse é um assunto já um tanto quanto conhecido da maioria dos desenvolvedores mas acho interessante registrar aqui pois ainda vejo muita gente concatenando strings sem perceber que existem outras alternativas menos custosas.

A classe System.String representa textos como uma coleção de caracteres Unicode. Um objeto String é então uma coleção sequencial de objetos do tipo System.Char que representam a string.

Uma característica que alguns não conhecem é que a string é imutável, ou seja, o seu valor não pode ser modificado (read-only). Verifique que a maioria dos métodos existentes na classe System.String retornam uma nova string e não modificam a instância da mesma.

Quando concatenamos a string com uma outra string, por exemplo...

string str1 = "a";
str1 = str1 + "b";

uma nova instância da classe string é criada e atribuída a variável str1. Isso faz com que códigos que concatenam strings extensivamente utilizem muita memória e consequentemente tenham uma perda de performance.

A classe System.Text.StringBuilder representa então uma string mutável de caracteres e representa um ganho de performance enorme se utilizada em nosso código.

Vou demonstrar abaixo dois códigos que podem ser utilizados em uma aplicação Console e que irão demonstrar a diferença de performance quando utilizamos StringBuilder. Para realizar a medição do tempo utilizaremos a classe System.Diagnostics.Stopwatch.

Digamos então que temos o seguinte código:

using System;
using System.Text;
using System.Diagnostics;

namespace CSharpStringBuilderPerformance
{
    // Main program
    class Program
    {
        static void Main(string[] args)
        {
            string suaString = "";

            // cria StopWatch
            Stopwatch stopWatch = new Stopwatch();

            // inicia medição do tempo
            stopWatch.Start();

            // loop para teste
            for (int i = 0; i < 10000; ++i)
                suaString += "Número: " + i.ToString() + "\n";

            // finaliza medição do tempo
            stopWatch.Stop();

            // tempo decorrido
            Console.WriteLine(stopWatch.ElapsedMilliseconds);
        }
    }
}

O que o código faz é bem simples, somente cria uma variável chamada suaString e com um loop de 0 a 9999 realiza concatenação da string "Número: (contador)" seguido de uma nova linha.

Os métodos Start e Stop do objeto da classe Stopwatch realizam respectivamente o início da medida do tempo e o final da medida do tempo.

Realizando o processamento do código acima 10 vezes tive os seguintes resultados computados em milisegundos:

1728
1708
1720
1712
1709
1726
1717
1700
1731
1702

Obs: Dependendo do seu hardware você pode ter valores diferentes (óbvio).

Ok, agora vamos utilizar a classe StringBuilder e o método AppendLine da mesma para concatenar a string. Vou somente colocar o código do método Main para simplificar melhor o exemplo.

static void Main(string[] args)
{
    // cria StringBuilder
    StringBuilder stringBuilder = new StringBuilder();

    // cria StopWatch
    Stopwatch stopWatch = new Stopwatch();

    // inicia medição do tempo
    stopWatch.Start();

    // loop para teste
    for (int i = 0; i < 10000; ++i)
        stringBuilder.AppendLine("Número: " + i.ToString());

    // finaliza medição do tempo
    stopWatch.Stop();

    // tempo decorrido
    Console.WriteLine(stopWatch.ElapsedMilliseconds);
}

A idéia é substituir o objeto string por um objeto StringBuilder e utilizar o método AppendLine. Se existir a necessidade de transformar o StringBuilder em String novamente é só utilizarmos o método ToString().

Processando o código com StringBuilder 10 vezes temos o incrível resultado abaixo:

6
5
7
6
5
8
9
10
9
6

Perceberam a diferença de performance? Portanto utilizem o StringBuilder sempre que possível.

Alguns links de ajuda:

String Class
http://bit.ly/6ebptP

StringBuilder Class
http://bit.ly/64pDlE

Stopwatch Class
http://bit.ly/8TcpCG

Hello World

Olá pessoal, meu nome é Ari Cristiano Raimundo e estou inaugurando aqui um blog técnico que irá conter diversos posts com assuntos relacionados às tecnologias existentes no Microsoft .NET Framework.

A idéia de criar o blog veio da necessidade de tentar compartilhar e adquirir mais conhecimento com os colegas desenvolvedores. Alguns dos posts estarão relacionados com assuntos que respondo nos fóruns do MSDN da Microsoft Brasil além de dicas e prováveis novidades do mundo .NET.

Profissionalmente trabalho há 12 anos como desenvolvedor de aplicações nas áreas de Engenharia Geomática e Engenharia de Transportes.

Espero que gostem.