A instrução foreach repete um grupo de comandos incorporados para cada elemento em uma matriz ou uma coleção de objetos que implementa a interface de System.Collections.IEnumerable ou System.Collections.Generic.IEnumerable <T>. A instrução foreach é usado para percorrer a coleção para obter as informações que você quer, mas não pode ser usado para adicionar ou remover itens da coleção de origem para evitar efeitos colaterais imprevisíveis. Se você precisar adicionar ou remover itens da coleção de origem, use um loop for.

Bom, vamos trabalhar com uma fonte de dados que no caso é uma coleção de string (array), queremos percorrer todos seus elementos e exibir na tela, existe duas maneiras, utilizar a estrutura de repetição convencional (for) ou o (foreach). Fonte de dados a ser usada como exemplo:

//Array de String
string[] arrayDeNomes = new string[]
{
    "Roberto",
    "Ingrid",
    "Aline",
    "Janice"
};

Resultado:

 
Vejamos abaixo a diferença de sintaxe entre as duas estrutura de repetição (for) e (foreach). No (for) convencional necessitamos de um índice, onde através dele informaremos a nossa fonte de dados qual é o índice do elemento que estamos procurando, tendo como seguinte resultado:

for (int i = 0; i < arrayDeNomes.Length; i++)
{
    Console.Write("Nome: {0}", arrayDeNomes[i]);
    Console.Write("\n");
}

No (foreach) não existe um limite do looping, pois isto já está implícito na própria coleção, não é necessário utilizarmos um índice ou seja, você só precisa se preocupar em manipular a sua fonte de dados atual, para ser mais exato o objeto que ele esta retornando, vejamos abaixo um exemplo:


foreach (var nomePessoa in arrayDeNomes)
{
    Console.Write("Nome: {0}", nomePessoa);
    Console.Write("\n");
}

No exemplo mostrado acima, imagine que ao fazer o primeiro looping, ele atribui a primeira string contida no nosso
arrayDeNomes, no caso arrayDeNomes[0] que nos retorna o nome 
Roberto, armazenado o mesmo na variável (var) chamada 
nomePessoa, logo em seguida é impresso na tela para o usuário. No C#, não é necessário para implementar uma interface de coleção IEnumerable ou IEnumerator para
 ser compatível com foreach. 

Se a classe tem o GetEnumeratorMoveNextReset, e Current membros, ele funcionará com foreach. A ideia deste mini artigo não é mostrar que um é melhor que o outro, mais sim tentar entender pelo menos o minimo de como se funciona um foreach.