Visitor is one of the most boilerplate-ridden patterns of all and has the drawbacks regarding non-extensibility that you mention. It is itself a sloppy workaround to introduce double dispatch into a single-dispatch language. When you consider all its drawbacks, resorting to reflection is not such a terrible choice.
In fact, reflection is not a very bad choice in any case: consider how much today's code is written in dynamic languages, in other words using nothing but reflection, and the applications don't fall apart because of it.
Type safety has its merits, certainly, but when you find yourself hitting the wall of static typing and single dispatch, embrace reflection without remorse. Note also that, with proper caching of Method
objects, reflective method invocation is almost as fast as static invocation.