Para hacerlo lo más limpio posible, me gusta dejar que el compilador haga todo el trabajo. No hay yesos (por lo que en realidad es seguro para tipos). No se utilizan bibliotecas de terceros (System.Linq) (sin sobrecarga de tiempo de ejecución).
public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
{
return arr;
}
// Y para usar el código:
String[] arr = new String[0];
arr.GetEnumerable().GetEnumerator()
Esto aprovecha la magia del compilador que mantiene todo limpio.
El otro punto a tener en cuenta es que mi respuesta es la única respuesta que realizará la verificación en tiempo de compilación.
Para cualquiera de las otras soluciones, si el tipo de "arr" cambia, el código de llamada se compilará y fallará en tiempo de ejecución, lo que resultará en un error de ejecución.
Mi respuesta hará que el código no se compile y, por lo tanto, tengo menos posibilidades de enviar un error en mi código, ya que me indicaría que estoy usando el tipo incorrecto.