domingo, 24 de maio de 2009

C# - Herança

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/24/C-Heranca.aspx


Antes de mais nada, existem alguns pontos importantes sobre herança em C#:

1 - Toda classe é derivada da classe object e a classe object é a única que não é derivada de nenhuma outra classe;

2 - C# não tem herança múltipla;

3 - O construtor de uma classe derivada sempre chama o construtor da classe base explícita ou implicitamente e depois executa seu código;

4 - O access modifier protected é usado para tornar a variável de uma determinada classe acessível somente pelas classes derivadas dela;

5 - Para sobrepôr um método de uma classe base em uma classe derivada, esse método precisa ter, depois do access modifier, a palavra-chave override e o método na classe base deve ter, por exemplo, a palavra-chave virtual.

O exemplo abaixo é mais um baseado no livro do Deitel.


Classe base:

   1:  class EmpregadoComissionado

   2:  {

   3:      private string nome;

   4:      private string sobrenome;

   5:      private string rg;

   6:      private double vendas;

   7:      private double comissao;

   8:   

   9:      public string Nome

  10:      {

  11:          get

  12:          {

  13:              return nome;

  14:          }

  15:   

  16:          private set

  17:          {

  18:              nome = value;

  19:          }

  20:      }

  21:   

  22:      public string Sobrenome

  23:      {

  24:          get

  25:          {

  26:              return sobrenome;

  27:          }

  28:   

  29:          private set

  30:          {

  31:              sobrenome = value;

  32:          }

  33:      }

  34:   

  35:      public string RG

  36:      {

  37:          get

  38:          {

  39:              return rg;

  40:          }

  41:   

  42:          private set

  43:          {

  44:              rg = value;

  45:          }

  46:      }

  47:   

  48:      public double Vendas

  49:      {

  50:          get

  51:          {

  52:              return vendas;

  53:          }

  54:   

  55:          private set

  56:          {

  57:              vendas = (value <= 0) ? 0 : value;

  58:          }

  59:      }

  60:   

  61:      public double Comissao

  62:      {

  63:          get

  64:          {

  65:              return comissao;

  66:          }

  67:   

  68:          private set

  69:          {

  70:              comissao = (value <= 0  value >= 100) ? 0 : value;

  71:          }

  72:      }

  73:   

  74:   

  75:      public virtual double SalarioGanho()

  76:      {

  77:          return Comissao * Vendas;

  78:      }

  79:   

  80:      public EmpregadoComissionado(string Nome, string Sobrenome, string RG, double Vendas, double Comissao)

  81:      {

  82:          this.Nome = Nome;

  83:          this.Sobrenome = Sobrenome;

  84:          this.RG = RG;

  85:          this.Vendas = Vendas;

  86:          this.Comissao = Comissao;

  87:      }

  88:  }

Classe derivada:

   1:  class EmpregadoComissionadoMaisSalarioBase : EmpregadoComissionado

   2:  {

   3:      private double salarioBase;

   4:   

   5:      public double SalarioBase

   6:      {

   7:          get

   8:          {

   9:              return salarioBase;

  10:          }

  11:   

  12:          private set

  13:          {

  14:              salarioBase = (value <= 0) ? 0 : value;

  15:          }

  16:      }

  17:   

  18:   

  19:      public override double SalarioGanho()

  20:      {

  21:          return base.SalarioGanho() + SalarioBase;

  22:      }

  23:   

  24:   

  25:      public EmpregadoComissionadoMaisSalarioBase(string Nome, string Sobrenome, string RG, double Vendas, double Comissao, double Salario) : base(Nome, Sobrenome, RG, Vendas, Comissao)

  26:      {

  27:          this.SalarioBase = Salario;

  28:      }

  29:  }


Aplicação das classes:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          EmpregadoComissionado empregado1 = new EmpregadoComissionado("Jorge", "Silveira", "23333334", 250000, 0.10);

   6:   

   7:          Console.WriteLine("Empregado 1 - Comissionado");

   8:          Console.WriteLine("Nome: " + empregado1.Nome);

   9:          Console.WriteLine("Sobrenome: " + empregado1.Sobrenome);

  10:          Console.WriteLine("RG: " + empregado1.RG);

  11:          Console.WriteLine("Valor das vendas: " + empregado1.Vendas.ToString());

  12:          Console.WriteLine("% de comissão: " + empregado1.Comissao.ToString());

  13:          Console.WriteLine("Salário total: " + empregado1.SalarioGanho().ToString());

  14:   

  15:   

  16:          EmpregadoComissionadoMaisSalarioBase empregado2 = new EmpregadoComissionadoMaisSalarioBase("Carlos", "Franco", "764840392", 170430, 0.05, 3500);

  17:   

  18:          Console.WriteLine("\n\nEmpregado 2 - Comissionado + Assalariado");

  19:          Console.WriteLine("Nome: " + empregado2.Nome);

  20:          Console.WriteLine("Sobrenome: " + empregado2.Sobrenome);

  21:          Console.WriteLine("RG: " + empregado2.RG);

  22:          Console.WriteLine("Valor das vendas: " + empregado2.Vendas.ToString());

  23:          Console.WriteLine("% de comissão: " + empregado2.Comissao.ToString());

  24:          Console.WriteLine("Salário base: " + empregado2.SalarioBase.ToString());

  25:          Console.WriteLine("Salário total: " + empregado2.SalarioGanho().ToString());

  26:   

  27:   

  28:          Console.ReadLine();

  29:      }

  30:  }

terça-feira, 19 de maio de 2009

C# - readonly Instance Variables e Constantes

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/19/C-readonly-Instance-Variables-e-Constantes.aspx


O conceito e a diferença são bem simples.

As variáveis que são criadas como readonly podem ser declaradas sem que um valor seja atribuído a ela. Assim que um valor é atribuído, nenhum outro pode sobrescrevê-lo. Exemplo:

private readonly int VARIABLENAME;

Uma constante, quando declarada precisa já receber um valor:

private const string NOMEDACONSTANTE;

C# - Garbage Collection e Destrutores

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/19/C-Garbage-Collection-e-Destrutores.aspx


O Common Language Runtime (CLR) faz o gerenciamento automático de memória usando o garbage collector para recuperar a memória usada por objetos que não estão mais sendo usados, então a memória pode ser usada por outros objetos.

Para chamar um destrutor, o C# usa um ~ (tio) antes do nome do construtor (sem parâmetros). Ao atribuir null a um objeto, o garbage collector não é executado no mesmo momento, o que significa que o objeto continua na memória e o método destrutor não é chamado na mesma hora. Não é possível determinar quando o garbage collector é chamado, portanto é sempre aconselhável evitar o uso de destrutores.

O código de exemplo abaixo utiliza destrutores, porém é necessário utilizar os métodos Collect() e WaitForPendingFinalizers() presentes na classe GC, da namespace System, para que o código funcione corretamente. O método Collect() chama o garbage collector, porém ele roda em um thread em paralelo com o resto do código. Isso força a utilização de WaitForPendingFinalizers() para esperar que o thread do garbage collector termine a sua execução para depois continuar o código no thread que chamou o método.

Segue o exemplo:

   1:  class Empregado

   2:  {

   3:      private string primeiroNome;

   4:      private string ultimoNome;

   5:      private static int contador = 0;

   6:          

   7:      public Empregado(string nome, string sobrenome)

   8:      {

   9:          contador++;

  10:          primeiroNome = nome;

  11:          ultimoNome = sobrenome;

  12:      }

  13:   

  14:      ~Empregado()

  15:      {

  16:          contador--;

  17:      }

  18:   

  19:      public string Nome

  20:      {

  21:          get

  22:          {

  23:              return primeiroNome;

  24:          }

  25:      }

  26:   

  27:      public string Sobrenome

  28:      {

  29:          get

  30:          {

  31:              return ultimoNome;

  32:          }

  33:      }

  34:   

  35:      public static int Contador

  36:      {

  37:          get

  38:          {

  39:              return contador;

  40:          }

  41:      }

  42:  }


A classe do programa:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Empregado empregado1 = new Empregado("Thiago", "Milaneze");

   6:          Empregado empregado2 = new Empregado("Eric", "Milaneze");

   7:   

   8:          Console.WriteLine("Número de empregados: " + Empregado.Contador.ToString());

   9:          Console.WriteLine("Empregado 1: " + empregado1.Nome + " " + empregado1.Sobrenome);

  10:          Console.WriteLine("Empregado 2: " + empregado2.Nome + " " + empregado2.Sobrenome);

  11:   

  12:          empregado1 = null;

  13:          empregado2 = null;

  14:   

  15:          GC.Collect();

  16:          GC.WaitForPendingFinalizers();

  17:   

  18:          Console.WriteLine("\nNúmero de empregados: " + Empregado.Contador.ToString());

  19:   

  20:          Console.ReadLine();

  21:      }

  22:  }

domingo, 17 de maio de 2009

C# - Sobrecarga do método construtor

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/17/C-Sobrecarga-do-metodo-construtor.aspx


O código no exemplo abaixo desse post mostra uma maneira de fazer a sobrecarga do método construtor usando a palavra-chave this para fazer uma chamada a um construtor através de outro construtor.

Nesse caso, o código:

public mySampleClass() : this(10) { }


é equivalente a:

public mySampleClass()
{
mySampleClass(10);
}


Vamos ao exemplo desse post.

   1:  class Time

   2:  {

   3:      private string h, m, s;

   4:        

   5:      public Time() : this("00", "00", "00") { }

   6:   

   7:      public Time(string hora) : this(hora, "00", "00") { }

   8:   

   9:      public Time(string hora, string minuto) : this(hora, minuto, "00") { }

  10:   

  11:      public Time(Time time) : this(time.h, time.m, time.s) { }

  12:   

  13:      public Time(string hora, string minuto, string segundo)

  14:      {

  15:          h = hora;

  16:          m = minuto;

  17:          s = segundo;

  18:      }

  19:   

  20:      public string ImprimirHora()

  21:      {

  22:          return h + ":" + m + ":" + s;

  23:      }

  24:  }


Usando esse código:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Time hora1 = new Time();

   6:          Console.WriteLine("Hora 1: " + hora1.ImprimirHora());

   7:   

   8:          Time hora2 = new Time("02");

   9:          Console.WriteLine("Hora 2: " + hora2.ImprimirHora());

  10:   

  11:          Time hora3 = new Time("02", "10");

  12:          Console.WriteLine("Hora 3: " + hora3.ImprimirHora());

  13:   

  14:          Time hora4 = new Time("02", "10", "50");

  15:          Console.WriteLine("Hora 4: " + hora4.ImprimirHora());

  16:   

  17:          // o objeto hora4 dessa vez é passado como parâmetro

  18:          Time hora5 = new Time(hora4);

  19:          Console.WriteLine("Hora 5: " + hora5.ImprimirHora());

  20:   

  21:          Console.ReadLine();

  22:      }

  23:  }

C# - Indexadores

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/17/C-Indexadores.aspx


Indexadores permitem acessar uma lista de elementos através do nome do objeto usando a palavra-chave this. Usando C# convencional, um elemento de um array é acessado usando-se como índice um valor inteiro (ex.: dimensoes[1]). Com indexadores, é possível utilizar strings (ex.: caixa["largura"], onde caixa é um objeto).

Embora indexadores sejam usados como arrays, os indexadores são declarados como propriedades em uma classe. Ao contrário das propriedades, onde é possível escolher qualquer nome, os indexadores são declarados com a palavra-chave this.

A sintaxe é a seguinte:


   1:  accessModifier returnType this[ IndexType1 name1, IndexType2 name2, ... ]

   2:  {

   3:      get

   4:      {

   5:         // use name1, name2, ... here to get data

   6:      }

   7:      set

   8:      {

   9:         // use name1, name2, ... here to set data

  10:      }

  11:  }


Os códigos abaixo dão exemplos de como declarar e depois de como acessar indexadores.


   1:  class Caixa

   2:  {

   3:      private double[] dimensoes = new double[3];

   4:      private string[] medidas = { "largura", "altura", "comprimento" };

   5:   

   6:      public Caixa(double largura, double altura, double comprimento)

   7:      {

   8:          dimensoes[0] = largura;

   9:          dimensoes[1] = altura;

  10:          dimensoes[2] = comprimento;

  11:      }

  12:   

  13:      public double this[int index]

  14:      {

  15:          get

  16:          {

  17:              if (index >= 0 && index < dimensoes.Length)

  18:                  return dimensoes[index];

  19:              else

  20:                  return -1;

  21:          }

  22:   

  23:          set

  24:          {

  25:              if (index >= 0 && index < dimensoes.Length)

  26:                  dimensoes[index] = value;

  27:          }

  28:      }

  29:   

  30:      public double this[string medida]

  31:      {

  32:          get

  33:          {

  34:              int i = 0;

  35:   

  36:              foreach (string palavra in medidas)

  37:                  if (palavra == medida)

  38:                      return dimensoes[i];

  39:                  else

  40:                      i++;

  41:   

  42:              return -1;

  43:          }

  44:   

  45:          set

  46:          {

  47:              int i = 0;

  48:   

  49:              while (i < medidas.Length)

  50:              {

  51:                  if (medida == medidas[i])

  52:                      dimensoes[i] = value;

  53:                     

  54:                  i++;

  55:              }

  56:          }

  57:      }

  58:  }


Exemplo de como usar os indexadores:


   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Caixa caixa = new Caixa(10, 20, 30);

   6:   

   7:          Console.WriteLine("Valores iniciais");

   8:          Console.WriteLine("Largura: " + caixa[0]);

   9:          Console.WriteLine("Altura: " + caixa[1]);

  10:          Console.WriteLine("Comprimento: " + caixa[2]);

  11:   

  12:          caixa[0] = 40;

  13:          caixa[1] = 50;

  14:          caixa[2] = 60;

  15:   

  16:          Console.WriteLine("\nValores mudados e acessados com indexador do tipo int");

  17:          Console.WriteLine("Largura: " + caixa[0]);

  18:          Console.WriteLine("Altura: " + caixa[1]);

  19:          Console.WriteLine("Comprimento: " + caixa[2]);

  20:   

  21:          caixa["largura"] = 70;

  22:          caixa["altura"] = 80;

  23:          caixa["comprimento"] = 90;

  24:   

  25:          Console.WriteLine("\nValores mudados e acessados com indexadir do tipo string");

  26:          Console.WriteLine("Largura: " + caixa["largura"]);

  27:          Console.WriteLine("Altura: " + caixa["altura"]);

  28:          Console.WriteLine("Comprimento: " + caixa["comprimento"]);

  29:   

  30:          Console.ReadLine();

  31:      }

  32:  }

domingo, 10 de maio de 2009

Problema: Firefox pedindo senha no IIS, o IE não pede

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/10/Problema-Firefox-pedindo-senha-no-IIS-o-IE-nao-pede.aspx


Esse problema ocorria quando eu ia acessar http://localhost/ pelo Firefox. Buscando em alguns fóruns, encontrei gente falando pra mudar as configurações do IIS, permitir logon anônimo, entre outras coisas. Nada funcionou.

O que funcionou bem foi seguir os seguintes passos:

1 - Digitar about:config na barra de endereços;

2 - Fazer uma busca por ntlm;

3 - Para mim, retornaram 3 entradas. Dei um duplo clique em network.automatic.ntlm.auth.trusted.uris e digitei localhost;

Depois disso deu certo. Ele passa a acessar localhost sem precisar de senha. Isso ocorre para os alias e subdiretórios também.

terça-feira, 5 de maio de 2009

C# - Operador ternário

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/05/C-Operador-ternario.aspx


É uma maneira rápida e compacta de expressar if-else.

A sintaxe é a seguinte:
valor = condição ? expressão : expressão2

Essa linha pode ser traduzida utilizando-se if-else:
if(condição)
valor = expressão
else
valor = expressão2

segunda-feira, 4 de maio de 2009

C# - Usando parâmetros de linha de comando

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/04/C-Usando-parametros-de-linha-de-comando.aspx


É possível passar parâmetros de linha de comando incluindo um parâmetro do tipo string[] na lista de parâmetros do método Main da aplicação. Por convenção, o nome do parâmetro é args.

Quando uma aplicação é executada através do Prompt de Comandos, o ambiente de execução passa os parâmetros de linha de comando que aparecem depois do nome da aplicação para o metodo Main da aplicação como um array de strings chamado args. O número de parâmetros passados pode ser obtido através da propriedade Length do array.

Exemplo: "ConsoleApplication2 a b" passa dois parâmetros (a e b) para a aplicação ConsoleApplication.exe. O primeiro parâmetro pode ser acessado como args[0] e o segundo como args[1].

O código abaixo faz a leitura de dois parâmetros e mostra os valores entre eles.


   1:  static void Main(string[] args)

   2:  {

   3:      if (args.Length != 2)

   4:          Console.WriteLine("Erro: Digite os 2 argumentos");

   5:      else

   6:          for (int i = Convert.ToInt32(args[0]); i <= Convert.ToInt32(args[1]); i++)

   7:              Console.Write("." + i.ToString() + ".");

   8:   

   9:          Console.Read();

  10:  }

domingo, 3 de maio de 2009

C# - Lista de argumentos variável

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/03/C-Lista-de-argumentos-variavel.aspx


Para passar um número variável de parâmetros para um método, deve-se usar a palavra-chave params seguida do parâmetro, que deve ser um array. Esse parâmetro deve ser o último do método.

No exemplo abaixo é possível verificar um exemplo que tira a média dos parâmetros passados ao método Media(params int[] numeros).


   1:  class Program

   2:  {

   3:      static double Media(params int[] numeros)

   4:      {

   5:          double resultado = 0;

   6:   

   7:          foreach (int numero in numeros)

   8:              resultado += numero;

   9:   

  10:          return resultado / numeros.Length;

  11:      }

  12:          

  13:      static void Main(string[] args)

  14:      {

  15:          Console.WriteLine("Média: " + Media(5, 10));

  16:          Console.WriteLine("Média: " + Media(10, 50, 90));

  17:          Console.Read();

  18:      }

  19:  }

C# - Criando arrays multidimensionais

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/03/C-Criando-arrays-multidimensionais.aspx


O exemplo de código abaixo mostra a sintaxe básica para criação de arrays multidimensionais (nesse caso de duas dimensões) e dois for para popular o array:

   1:  int[,] array = new int[2, 5];

   2:   

   3:  for(int linha = 0; linha < array.GetLength(0); linha++)

   4:  {

   5:      Console.WriteLine("Linha " + linha.ToString());

   6:                  

   7:      for (int coluna = 0; coluna < array.GetLength(1); coluna++)

   8:      {

   9:          Console.Write("." + coluna.ToString() + ".");

  10:      }

  11:   

  12:      Console.WriteLine("\n");

  13:  }

A novidade é o método GetLength() nas linhas 3 e 7. Esse método recebe como parâmetro a dimensão do array e retorna o número de elementos pra essa dimensão. No caso do array acima, ele possui 2 posições na dimensão 0 e 5 posições na dimensão 1. Portanto, array.GetLength(0) = 2 e array.GetLength(1) = 5.

C# - Passando arrays como parâmetro para métodos

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/03/C-Passando-arrays-como-parametro-para-metodos.aspx


Para passar um array como parâmetro a algum método, basta passá-lo sem os colchetes, como abaixo:

   1:  int[] array = new int[5];

   2:  teste.dobrarArray(array);

IMPORTANTE: O array é uma variável que "guarda" um objeto, mas não guarda o objeto em si. Ao invés disso, o array guarda uma referência a esse objeto (o local na memória onde esse objeto está).

No código acima, todos os elementos desse array são passados como parâmetro na linha 2. Por questões de performance, por default, o que é passado é apenas uma referência do array, ou seja, o espaço em memória onde o array está armazenado. Isso significa que as mudanças feitas a qualquer elemento desse array dentro do método implicarão em mudanças na variável do chamador desse método, pois o parâmetro foi passado por referência.

Resumindo: Por padrão, qualquer array ou objeto que é passado como parâmetro a um método, é passado por referência. Para saber mais sobre a diferença entre passar um valor, por valor ou referência: http://ericmilaneze.blogspot.com/2009/04/c-metodos-passando-parametros-por-valor.html

No caso de precisar passar um elemento de um array como parâmetro a um método, esse elemento (ex.: array[1]) é passado por valor ou por referência? Isso vai depender se foram usadas as palavras-chave ref ou out, ou nenhuma das duas. Se nenhuma foi usada, é passado por valor, caso contrário, por referência. Nesse caso, aplicam-se as mesmas regras no seguinte post: http://ericmilaneze.blogspot.com/2009/04/c-metodos-passando-parametros-por-valor.html

Apesar do array já ser uma variável que guarda uma referência e ser passado por padrão como referência a um método, existe uma diferença entre passar essa referência por referência ou por valor (utilizando a palavra-chave ref ou não). Quando se passa uma referência por referência, existe a possibilidade de recriar essa referência dentro do método, caso contrário não. O exemplo abaixo ilustra essa diferença.

Exemplo:

   1:  class ArrayReferenceTest

   2:  {

   3:      public void dobrarArray(int[] array)

   4:      {

   5:          for (int i = 0; i < array.Length; array[i] = i++ * 2) ;

   6:   

   7:          array = new int[3];

   8:      }

   9:   

  10:      public void dobrarArray(ref int[] array)

  11:      {

  12:   

  13:          for (int i = 0; i < array.Length; array[i] = i++ * 2) ;

  14:   

  15:          array = new int[3];

  16:      }

  17:  }


Utilizando o exemplo:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          ArrayReferenceTest teste = new ArrayReferenceTest();

   6:   

   7:          int[] array = new int[5];

   8:   

   9:          // populando o array

  10:          for (int i = 0; i < array.Length; array[i] = i++) ;

  11:   

  12:          foreach (int i in array)

  13:              Console.Write("." + i.ToString() + ".");

  14:   

  15:          Console.WriteLine("\n");

  16:   

  17:   

  18:          // executa o método que multiplica por 2 cada elemento

  19:          teste.dobrarArray(array);

  20:   

  21:          foreach (int i in array)

  22:              Console.Write("." + i.ToString() + ".");

  23:   

  24:   

  25:          Console.WriteLine("\n");

  26:   

  27:   

  28:          // executa o método que multiplica por 2 cada elemento

  29:          teste.dobrarArray(ref array);

  30:   

  31:          foreach (int i in array)

  32:              Console.Write("." + i.ToString() + ".");

  33:   

  34:          Console.ReadLine();

  35:      }

  36:  }

Na classe ArrayReferenceTest, nas linhas 7 e 15, o array é recriado. Na linha 7, o código não possui nenhum efeito, pois o array não foi passado por referência. Já na linha 15, o array é recriado e pode ser, inclusive, redimensionado. Após ser recriado, não existe nada que popule os elementos desse array, portanto eles passam a ter um valor int default: 0.

sexta-feira, 1 de maio de 2009

C# - Usando foreach para percorrer cada elemento de um array

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/01/C-Usando-foreach-para-percorrer-cada-elemento-de-um-array.aspx

Para percorrer cada elemento de um array é possível utilizar um for que rode enquanto uma determinada variável for menor que a largura do array (usando a propriedade Length). Essa idéia me parece mais interessante quando a intenção é popular o array.

Quando a idéia é fazer leitura e apresentação dos dados, o foreach me parece uma solução mais rápida. A sintaxe é a seguinte:

foreach (tipo identicador in NomeDoArray)
código;

tipo: pode ser int, float, string, enfim... é o tipo da variável, que deve ser o mesmo tipo do array;
identificador: será o nome do elemento atual do array em cada iteração; exemplo: escrever "identificador" na segunda iteração é a mesma coisa que escrever "NomeDoArray[1]";
NomeDoArray: o array que será manipulado.


Exemplo:

   1:  const int NUM_DE_VALORES = 10;

   2:  int[] valores = new int[NUM_DE_VALORES];

   3:   

   4:  // populando o array valores

   5:  for (int i = 0; i < NUM_DE_VALORES; valores[i] = i++) ;

   6:   

   7:  foreach (int i in valores)

   8:      Console.WriteLine(i.ToString());

   9:   

  10:  Console.ReadLine();