Para deixar o mais limpo possível, gosto de deixar o compilador fazer todo o trabalho. Não há casts (portanto, é realmente seguro para tipos). Nenhuma biblioteca de terceiros (System.Linq) é usada (sem sobrecarga de tempo de execução).
public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
{
return arr;
}
// E para usar o código:
String[] arr = new String[0];
arr.GetEnumerable().GetEnumerator()
Isso tira vantagem de alguma mágica do compilador que mantém tudo limpo.
O outro ponto a ser observado é que minha resposta é a única que fará a verificação em tempo de compilação.
Para qualquer uma das outras soluções, se o tipo de "arr" mudar, o código de chamada será compilado e falhará no tempo de execução, resultando em um bug de tempo de execução.
Minha resposta fará com que o código não compile e, portanto, tenho menos chance de enviar um bug no meu código, pois isso me indicaria que estou usando o tipo errado.