Resolvi fazer este simples teste de performance para ver a diferença de tempo entre duas formas de concatenação de strings: usando a classe StringBuilder e usando o operador + para concatenação de strings em C#. O trecho de código que mede o tempo de execução entre as duas abordagens é bem simples, como segue:

   1: using System;
   2: using System.Text;
   3: using System.Diagnostics;
   4:  
   5: namespace TesteConcatStrings
   6: {
   7:     class Program
   8:     {
   9:         public static void Main(string[] args)
  10:         {
  11:             Stopwatch watch = new Stopwatch();
  12:  
  13:             // Testar concatenação usando StringBuilder
  14:             StringBuilder sb = new StringBuilder();
  15:  
  16:             watch.Start();
  17:             for (int i = 0; i < 10000; i++)
  18:             {
  19:                 sb.Append("Testando a performance de concatenação de strings. ");
  20:             }
  21:             watch.Stop();
  22:             Console.WriteLine(string.Format("Usando StringBuilder: {0} ms", 
  23:                                 watch.ElapsedMilliseconds));
  24:  
  25:             // Teste de concatenação usando o operador +
  26:             string str = string.Empty;
  27:  
  28:             watch.Start();
  29:             for (int i = 0; i < 10000; i++)
  30:             {
  31:                 str += "Testando a performance de concatenação de strings. ";
  32:             }
  33:             watch.Stop();
  34:             Console.WriteLine(string.Format("Usando operador + em string: {0} ms", 
  35:                                 watch.ElapsedMilliseconds));
  36:  
  37:             Console.ReadKey();
  38:         }
  39:     }
  40: }

Como podemos ver, cada teste é um loop for de 10000 iterações, onde em cada iteração é feita uma concatenação de strings. No primeiro usamos a classe StringBuilder e no segundo o operador + de concatenação de strings. Para medir o tempo, usamos a classe Stopwatch e os métodos Start() e Stop(). Ao fim da execução de cada teste, a propriedade ElapsedMilisecondes da classe Stopwatch retorna o resultado em milissegundos.

Agora, o resultado:

strconcat

Realmente a diferença é impressionante! É claro que o resultado pode (e com certeza vai) variar de máquina para máquina, mas já dá para ter noção do tamanho da diferença de cada uma das abordagens de concatenação de strings.

E se você ainda não tem o hábito de usar StringBuilder em seus projetos, reveja seus conceitos… =)

Referências externas:


Posted in: C# , .Net  Tags: , ,
Admin posted on August 19, 2009 05:11

Os arquivos de configuração .INI há um bom tempo foram substituídos no .Net pelos arquivos XML, muito mais flexíveis e padronizados. Entretanto, quando trabalhamos com sistemas legados, seja para fazer integrações, migrações ou o que quer que seja, acabamos nos deparando com os saudosos arquivos .INI. Ao invés de criar rotinas caseiras para trabalhar com estes arquivos, que tal uma biblioteca em C# que cumpra esse papel com louvor? A biblioteca Nini faz isto e muito mais: além dos arquivos .INI, ela abstrai o acesso a arquivos de configuração XML, .Net Config, Registry e argumentos de linha de comando. O site do projeto não possui nada, apenas os links para poder baixar, mas a documentação vem junto com o arquivo baixado.

Segue um exemplo do próprio manual da Nini:

; MyApp.ini
[Logging]
File Name = MyApp.log
MessageColumns = 5
MaxFileSize = 40000000000000

   1: // Usando C#
   2: using Nini.Config;
   3: IConfigSource source = new IniConfigSource("MyApp.ini");
   4:  
   5: string fileName = source.Configs["Logging"].Get("File Name");
   6: int columns = source.Configs["Logging"].GetInt("MessageColumns");
   7: long fileSize = source.Configs["Logging"].GetLong("MaxFileSize");
   1: 'E usando VB.Net
   2: Imports Nini.Config
   3:  
   4: Dim source As New IniConfigSource("MyApp.ini")
   5:  
   6: Dim fileName As String = source.Configs("Logging").Get("File Name")
   7: Dim columns As Integer = source.Configs("Logging").GetInt("MessageColumns")
   8: Dim fileSize As Long = source.Configs("Logging").GetLong("MaxFileSize")

Posted in: .Net , C#  Tags: , , ,

Neste post vou apresentar um aplicativo para Windows Mobile 6 que recebe como entrada o valor do litro do álcool, da gasolina e exibe uma mensagem dizendo qual dos dois é mais vantajoso abastecer, bastante útil quando o seu veículo é flex. Faça o download do código fonte do projeto: AlcoolGasolina.zip (56,97 kb). Caso você queira apenas o .cab do aplicativo para instalar em seu smartphone, ele está na pasta AlcoolGasolinaSetup/Release.

Requisitos:

O código é bem simples, o valor do litro do álcool é dividido pelo valor do litro da gasolina, se o resultado for maior ou igual a 0,7 compensa abastecer com gasolina, caso contrário, abasteça com álcool.

   1:  using System;
   2:  using System.Text;
   3:  using System.Windows.Forms;
   4:   
   5:  namespace AlcoolGasolina
   6:  {
   7:      public partial class frmPrincipal : Form
   8:      {
   9:          public frmPrincipal()
  10:          {
  11:              InitializeComponent();
  12:          }
  13:   
  14:          /// <summary>
  15:          /// Método de validação da entrada. Considera inválidos strings vazias e 
  16:          /// valores menores ou iguais a zero.
  17:          /// </summary>
  18:          /// <param name="valor">O valor de entrada, formato string</param>
  19:          /// <returns>True para válido, False para inválido.</returns>
  20:          private bool isValid(string valor)
  21:          {
  22:              // Não deve ser uma string vazia ou nula
  23:              if (String.IsNullOrEmpty(valor))
  24:                  return false;
  25:              try
  26:              {
  27:                  // deve ser um valor numérico válido
  28:                  double num = Convert.ToDouble(valor);
  29:   
  30:                  // não deve ser menor ou igual a zero
  31:                  if (num > 0)
  32:                      return true;
  33:                  else
  34:                      return false;
  35:              }
  36:              catch (Exception)
  37:              {
  38:                  return false;
  39:              }
  40:          }
  41:   
  42:          /// <summary>
  43:          /// Verifica se os valores digitados são válidos e, em caso positivo, 
  44:          /// faz o cálculo e apresenta a mensagem para o usuário informando
  45:          /// qual é mais viável abastecer, álcool ou gasolina. Se os valores 
  46:          /// não forem válidos para o cálculo, será exibida uma mensagem de 
  47:          /// alerta, informando que os valores de entrada são inválidos.
  48:          /// </summary>
  49:          /// <param name="sender"></param>
  50:          /// <param name="e"></param>
  51:          private void btnCalcular_Click(object sender, EventArgs e)
  52:          {
  53:              if (isValid(txtAlcool.Text.Trim()) && isValid(txtGasolina.Text.Trim()))
  54:              {
  55:                  double alcool = Convert.ToDouble(txtAlcool.Text.Trim());
  56:                  double gasolina = Convert.ToDouble(txtGasolina.Text.Trim());
  57:   
  58:                  double resultado = alcool / gasolina;
  59:                  if (resultado >= 0.7)
  60:                      lblResultado.Text = "Abasteça com Gasolina";
  61:                  else
  62:                      lblResultado.Text = "Abasteça com Álcool";
  63:              }
  64:              else
  65:              {
  66:                  MessageBox.Show("Valores de entrada inválidos.", 
  67:                                  "Erro", 
  68:                                  MessageBoxButtons.OK, 
  69:                                  MessageBoxIcon.Exclamation, 
  70:                                  MessageBoxDefaultButton.Button1);
  71:              }
  72:              txtAlcool.Text = string.Empty;
  73:              txtGasolina.Text = string.Empty;
  74:          }
  75:   
  76:          /// <summary>
  77:          /// Fecha a aplicação.
  78:          /// </summary>
  79:          private void mnuSair_Click(object sender, EventArgs e)
  80:          {
  81:              Application.Exit();
  82:          }
  83:   
  84:          /// <summary>
  85:          /// Menu "Sobre...", exibe uma mensagem com o nome da aplicação, 
  86:          /// nome do autor e endereço do blog do autor.
  87:          /// </summary>
  88:          private void mnuSobre_Click(object sender, EventArgs e)
  89:          {
  90:              StringBuilder mensagem = new StringBuilder("Álcool ou Gasolina\n\n");
  91:              mensagem.Append("Por Rogério Bragil\n\nBlog do Bragil - www.bragil.net");
  92:              MessageBox.Show(mensagem.ToString(), 
  93:                              "Sobre", 
  94:                              MessageBoxButtons.OK, 
  95:                              MessageBoxIcon.None, 
  96:                              MessageBoxDefaultButton.Button1);
  97:          }
  98:      }
  99:  }

 

 


Posted in: .Net , C# , Windows Mobile  Tags: , ,
Admin posted on August 6, 2009 10:12

Precisa fazer parsing de HTML em .Net? Experimente o HTML Agility Pack. Com ele você pode facilmente ler uma página HTML e acessar os seus elementos através de expressões XPath, ou então percorrer os nós da estrutura de árvore da página HTML. Vou mostrar aqui um exemplo prático, uma pequena aplicação Windows Forms que, dada uma URL, retorna todos os elementos a (links) existentes na página. Você pode alterar o programa para poder extrair conteúdo de sites, efetuar buscas, etc.

Acesse o site do HTML Agility Pack e faça o download do código fonte. Descompacte, abra o projeto no Visual Studio (2005 ou superior) e compile o projeto HtmlAgilityPack, que deverá gerar a dll com o mesmo nome na pasta bin do projeto. Com a dll criada, feche a solução atual (com o código do HTML Agility Pack) e crie um novo projeto Windows Application usando a linguagem C#. Adicione a referência para a dll do HTML Agility Pack, criada anteriormente. Adicione os seguintes controles no form:

  • TextBox, ID "txtUrl", onde será digitada a URL.
  • Button, ID "btnBusca", ao clicar esse botão, vai buscar a URL e processar.
  • ListBox, ID "lsbResultado", exibir os links encontrados na página.

 Agora, vamos para o código:

   1:  using System;
   2:  using HtmlAgilityPack;
   3:  using System.Windows.Forms;
   4:   
   5:  namespace PegaLinks
   6:  {
   7:      public partial class Form1 : Form
   8:      {
   9:          public Form1()
  10:          {
  11:              InitializeComponent();
  12:          }
  13:   
  14:          private void btnBusca_Click(object sender, EventArgs e)
  15:          {
  16:              try 
  17:              {
  18:                  HtmlWeb web = new HtmlWeb();
  19:                  // O método Load da classe HtmlWeb busca a página HTML e faz o parsing, atribuindo a
  20:                  // árvore do DOM (document object model) gerada ao objeto HtmlDocument
  21:                  HtmlAgilityPack.HtmlDocument doc = web.Load(@txtUrl.Text.Trim());
  22:                  
  23:                  // Aqui pegamos apenas o que interessa, os links (tags <a>), usando XPath
  24:                  HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("/html/body//a");
  25:                  if (nodes != null)
  26:                  {
  27:                      // Percorremos a coleção dos nós encontrados (elementos <a>) e pegamos apenas o 
  28:                      // atributo href e o inner text de cada nó.
  29:                      foreach (HtmlNode node in nodes)
  30:                      {
  31:                          HtmlAttribute att = node.Attributes["href"];
  32:                          // Colocamos cada elemento no ListBox
  33:                          lsbResultado.Items.Add(node.InnerText + "  (" + att.Value + ")");
  34:                      }
  35:                  }
  36:                  else
  37:                  {
  38:                      MessageBox.Show("Nenhum link encontrado");
  39:                  }
  40:              }
  41:              catch (Exception ex)
  42:              {
  43:                  MessageBox.Show(ex.Message);
  44:              }   
  45:          }
  46:      }
  47:  }

 

Com poucas linhas você tem o que precisa: a informação limpinha. Sem precisar mexer com complexas expressões regulares ou parsing manual de strings... Tudo rápido e fácil! Não se esqueça de associar o evento Click do botão com o método btnBusca_Click.


Posted in: C# , .Net  Tags: , , , ,

Validação é algo de suma importância, e que muitas vezes é colocada em segundo ou até terceito plano no desenvolvimento de aplicações. O NHibernate Validator é um poderoso framework de validação, que torna simples e objetiva a tarefa de validar os dados fornecidos pelos usuários para a sua aplicação. Ele possui vários recursos, como configuração dos validadores através de XML e de atributos, integração com NHibernate, entre outros. Vamos mostrar um exemplo simples, onde a configuração dos validadores será feita através de atributos decorando as propriedades da classe Usuario abaixo:

   1:  using NHibernate.Validator;
   2:   
   3:  public class Usuario
   4:  {
   5:      private int id;
   6:      private string nome;
   7:      private string email;
   8:      private DateTime dataNascimento;
   9:   
  10:      [Min(1, Message = "Id deve ser positivo")]
  11:      public int Id
  12:      {
  13:          get { return id; }
  14:          set { id = value; }
  15:      }
  16:   
  17:      [NotNullNotEmpty(Message = "Nome é obrigatório."),
  18:       Length(Max= 80, Message = "Nome deve ter no máximo 80 caracteres.")]
  19:      public string Nome
  20:      {
  21:          get { return nome; }
  22:          set { nome = value; }
  23:      }
  24:   
  25:      [Email(Message = "E-mail inválido."),
  26:       NotNullNotEmpty(Message = "E-mail é obrigatório.")]
  27:      public string Email
  28:      {
  29:          get { return email; }
  30:          set { email = value; }
  31:      }
  32:   
  33:      [Past(Message = "Data de nascimento deve estar no passado."),
  34:       NotNull(Message = "Data de nascimento é obrigatório.")]
  35:      public DateTime DataNascimento
  36:      {
  37:          get { return dataNascimento; }
  38:          set { dataNascimento = value; }
  39:      }
  40:  }

 

  Lembrando que é necessário referenciar a dll NHibernate.Validator.dll no projeto. Existem muitos outros atributos, como Digits (para valores numéricos), CreditCardNumber (número de cartões de crédito), IPAddress (endereços IP), além da possibilidade de criar atributos de validação customizados. Com a configuração dos validadores feita, é hora de testar se os dados recebidos pelo objeto serão válidos:

   1:  using NHibernate.Validator.Engine;
   2:   
   3:  static void Main(string[] args)
   4:  {
   5:       Usuario user = new Usuario();
   6:       user.Id = 10;
   7:       user.Nome = "Rogério Bragil";
   8:       user.Email = "rogerio";
   9:       user.DataNascimento = new DateTime(1978, 1, 27);
  10:       ValidatorEngine validator = new ValidatorEngine();
  11:       InvalidValue[] erros = validator.Validate(user);
  12:       foreach (InvalidValue erro in erros)
  13:       {
  14:           Console.WriteLine(erro.Message);
  15:       }
  16:       Console.ReadKey();
  17:  }

 

A execução deste exemplo exibe a seguinte mensagem:

E-mail inválido

devido ao fato da propriedade Email ter recebido a string "rogerio" (que não é um e-mail válido).

Esse exemplo foi uma pequena amostra dos recursos do NHibernate Validator. Há muito mais o que ser explorado, vale muito a pena dar uma lida na documentação e explorar mais recursos dessa poderosa ferramenta de validação.


Admin posted on September 29, 2008 07:09

Essa eu encontrei no Seven Library, uma rotina em C# para transformar valores decimais em sua representação por extenso em português do Brasil, usando reais como moeda. Algo bastante útil, difícil de encontrar pronto e meio chato de desenvolver. Segue o código:

   1:  using System;
   2:  using System.Collections;
   3:  using System.Text;
   4:   
   5:  namespace Teste
   6:  {
   7:   
   8:      public class NumeroPorExtenso
   9:      {
  10:   
  11:          private ArrayList numeroLista;
  12:   
  13:          private Int32 num;
  14:   
  15:          //array de 2 linhas e 14 colunas[2][14]
  16:          private static readonly String[,] qualificadores = new String[,] {
  17:  //                {"milésimo de real","milésimos de real"},//[0][0] e [0][1]
  18:                  {"centavo", "centavos"},//[1][0] e [1][1]
  19:                  {"", ""},//[2][0],[2][1]
  20:                  {"mil", "mil"},
  21:                  {"milhão", "milhões"},
  22:                  {"bilhão", "bilhões"},
  23:                  {"trilhão", "trilhões"},
  24:                  {"quatrilhão", "quatrilhões"},
  25:                  {"quintilhão", "quintilhões"},
  26:                  {"sextilhão", "sextilhões"},
  27:                  {"setilhão", "setilhões"},
  28:                  {"octilhão","octilhões"},
  29:                  {"nonilhão","nonilhões"},
  30:                  {"decilhão","decilhões"}
  31:                  };
  32:   
  33:          private static readonly String[,] numeros = new String[,] {
  34:                  {"zero", "um", "dois", "três", "quatro",
  35:                   "cinco", "seis", "sete", "oito", "nove",
  36:                   "dez","onze", "doze", "treze", "quatorze",
  37:                   "quinze", "dezesseis", "dezessete", "dezoito", "dezenove"},
  38:                  {"vinte", "trinta", "quarenta", "cinqüenta", "sessenta",
  39:                   "setenta", "oitenta", "noventa",null,null,null,null,null,null,null,null,null,null,null,null},
  40:                  {"cem", "cento",
  41:                   "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos",
  42:                   "setecentos", "oitocentos", "novecentos",null,null,null,null,null,null,null,null,null,null}
  43:                  };
  44:   
  45:          public NumeroPorExtenso() {
  46:              numeroLista = new ArrayList();
  47:          }
  48:   
  49:          public NumeroPorExtenso(Decimal dec) {
  50:              numeroLista = new ArrayList();
  51:              SetNumero(dec);
  52:          }
  53:   
  54:          public void SetNumero(Decimal dec) {
  55:              dec = Decimal.Round(dec,2);
  56:              dec = dec * 100;
  57:              num = Convert.ToInt32(dec);
  58:   
  59:              numeroLista.Clear();
  60:              if (num == 0)  {
  61:                  numeroLista.Add(0);
  62:                  numeroLista.Add(0);
  63:              } else {
  64:                  AddRemainder(100);
  65:   
  66:                  while (num != 0) {
  67:                      AddRemainder(1000);
  68:                  }
  69:   
  70:              }
  71:   
  72:          }
  73:   
  74:          private void AddRemainder(Int32 divisor) {
  75:              Int32 div = num / divisor;
  76:              Int32 mod = num % divisor;
  77:   
  78:              Int32[] newNum = new Int32[] {div,mod};
  79:   
  80:              numeroLista.Add(mod);
  81:   
  82:              num = div;
  83:          }
  84:   
  85:          private bool TemMaisGrupos(Int32 ps) {
  86:              while (ps > 0) {
  87:                  if ((Int32) numeroLista[ps] != 00 && !TemMaisGrupos(ps -1))
  88:                      return true;
  89:                  ps--;
  90:              }
  91:              return true;
  92:          }
  93:   
  94:          private bool EhPrimeiroGrupoUm() {
  95:              if ((Int32) numeroLista[numeroLista.Count-1] == 1)
  96:                  return true;
  97:              else
  98:                  return false;
  99:          }
 100:   
 101:          private bool EhUltimoGrupo(Int32 ps) {
 102:              return((ps > 0) && ((Int32) numeroLista[ps] != 0) || !TemMaisGrupos(ps - 1));
 103:          }
 104:   
 105:          private bool EhGrupoZero(Int32 ps) {
 106:              if (ps <= 0 || ps >= numeroLista.Count)
 107:                  return true;
 108:              return ((Int32) numeroLista[ps] == 0);
 109:          }
 110:   
 111:          private bool EhUnicoGrupo() {
 112:              if (numeroLista.Count <= 3)
 113:                  return false;
 114:   
 115:              if (!EhGrupoZero(1) && !EhGrupoZero(2))
 116:                  return false;
 117:   
 118:              bool hasOne = false;
 119:   
 120:              for (Int32 i=3; i < numeroLista.Count; i++) {
 121:                  if ((Int32) numeroLista[i] != 0) {
 122:                      if (hasOne)
 123:                          return false;
 124:                      hasOne = true;
 125:                  }
 126:              }
 127:              return true;
 128:          }
 129:   
 130:          private String NumToString(Int32 numero,Int32 escala) {
 131:              Int32 unidade = (numero % 10);
 132:              Int32 dezena = (numero % 100);
 133:              Int32 centena = (numero / 100);
 134:   
 135:              StringBuilder buf = new StringBuilder();
 136:   
 137:              if (numero != 0) {
 138:                  if (centena != 0) {
 139:                      if (dezena == 0 && centena == 1) {
 140:                          buf.Append(numeros[2,0]);
 141:                      } else {
 142:                          buf.Append(numeros[2,centena]);
 143:                      }
 144:                  }
 145:   
 146:                  if (buf.Length > 0 && dezena != 0) {
 147:                      buf.Append(" e ");
 148:                  }
 149:   
 150:                  if (dezena > 19) {
 151:                      dezena = dezena / 10;
 152:                      buf.Append(numeros[1,dezena-2]);
 153:                      if (unidade != 0) {
 154:                          buf.Append(" e ");
 155:                          buf.Append(numeros[0,unidade]);
 156:                      }
 157:                  } else if (centena == 0 || dezena != 0) {
 158:                      buf.Append(numeros[0,dezena]);
 159:                  }
 160:   
 161:                  buf.Append(" ");
 162:   
 163:                  if (numero == 1) {
 164:                      buf.Append(qualificadores[escala,0]);
 165:                  } else {
 166:                      buf.Append(qualificadores[escala,1]);
 167:                  }
 168:   
 169:              }
 170:              return buf.ToString();
 171:          }
 172:   
 173:          public String ToString() {
 174:              StringBuilder buf = new StringBuilder();
 175:   
 176:              Int32 numero = (Int32) numeroLista[0];
 177:              Int32 count;
 178:              for (count = numeroLista.Count -1; count > 0; count--) {
 179:                  if (buf.Length > 0 &&  !EhGrupoZero(count)) {
 180:                      buf.Append(" e ");
 181:                  }
 182:                  buf.Append(NumToString((Int32) numeroLista[count],count));
 183:              }
 184:   
 185:              if (buf.Length > 0) {
 186:   
 187:                  while (buf.ToString().EndsWith(" "))
 188:                      buf.Length = buf.Length -1;
 189:   
 190:                  if (EhUnicoGrupo()) {
 191:                      buf.Append(" de ");
 192:                  }
 193:   
 194:                  if (EhPrimeiroGrupoUm()) {
 195:                      buf.Insert(0,"h");
 196:                  }
 197:   
 198:                  if (numeroLista.Count == 2 && ((Int32) numeroLista[1] == 1)) {
 199:                      buf.Append(" real");
 200:                  } else {
 201:                      buf.Append(" reais");
 202:                  }
 203:   
 204:                  if ((Int32) numeroLista[0] != 0) {
 205:                      buf.Append(" e ");
 206:                  }
 207:              }
 208:   
 209:              if ((Int32) numeroLista[0] != 0) {
 210:                  buf.Append(NumToString((Int32) numeroLista[0],0));
 211:              }
 212:   
 213:              return buf.ToString();
 214:          }
 215:      }
 216:  }

 


Posted in: .Net , C#  Tags: ,
Admin posted on September 23, 2008 11:09

Uma rotina bem simples para forçar o download de arquivos em Asp.Net, evitando que eles sejam abertos no browser. Por exemplo, se você quiser forçar que o usuário baixe um arquivo de imagem ao invés de abrir no browser, esta função será útil.

   1:  ''' <summary>
   2:      ''' Rotina para forçar o download de arquivos
   3:      ''' </summary>
   4:      ''' <param name="caminhoArquivo">Caminho para o arquivo no sistema de arquivos</param>
   5:      ''' <param name="contentType">Content-Type do arquivo (opcional)</param>
   6:      Protected Sub ForceDownload(ByVal caminhoArquivo As String, _
   7:                                  Optional ByVal contentType As String = "application/octet-stream")
   8:          Dim arquivo As FileInfo = New FileInfo(caminhoArquivo)
   9:          Response.Clear()
  10:          Response.AddHeader("Content-Disposition", "attachment; filename=" + arquivo.Name)
  11:          Response.AddHeader("Content-Length", arquivo.Length.ToString())
  12:          Response.ContentType = contentType
  13:          Response.WriteFile(arquivo.FullName)
  14:          Response.End()
  15:      End Sub

 


Posted in: .Net , ASP.Net , VB.Net  Tags: , ,

Páginas

Calendário

«  September 2010  »
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
View posts in large calendar