So, do we have a clear winner or it’s more a matter of taste?
The first option has a fundamental flaw – it’s never going to be thread safe or safe if CreateUser relies on external resources, and other implementations may create in between your tests. In general, I tend to avoid this “pattern” because of this.
As for the other two options – it really comes down to whether the failure is expected to happen. If CreateUser would be expected to fail on a somewhat normal basis, the Try* pattern is my preference, as using exceptions essentially becomes using exceptions for control flow.
If the failure would truly be an exceptional case, then exceptions would be more understandable.