public es visible desde cualquier lugar.
internal es visible solo dentro de un ensamblaje
Suele utilizar internal solo para proteger las API internas. Por ejemplo, puede exponer varias sobrecargas de un método:
public int Add(int x, int y)
public int Add(int x,int y, int z)
Ambos llaman al método interno
internal int Add(int[] numbers)
Entonces puede poner mucha sofisticación en un método, pero "protegerlo" usando métodos de fachada que pueden ayudar al programador a llamar al método correctamente. (El método de implementación con el parámetro de matriz puede tener un límite arbitrario de valores, por ejemplo).
También vale la pena señalar que al usar Reflection, todos y cada uno de los métodos son invocables independientemente de su visibilidad. Otro "truco" para controlar / obtener acceso a API ocultas internamente.