I know so far that a local variable or a local property can be used as an alias like so
ClassA _aliasA;
_session.QueryOver(x => x.ClassA, () => _aliasA);
<
I needed to solve a similar issue and decided on an alias naming convention. Then where ever you needed to reuse the alias you can check for it using GetCriteriaByAlias() and add it if it is not there. Being able to reuse the alias is very handy if you have different select projections. This method is still problematic if someone disregards naming conventions, but then your unit tests should pick that up.
Project aProject = null;
if (root.UnderlyingCriteria.GetCriteriaByAlias("aProject") == null)
root.JoinAlias(i => i.Project, () => aProject);