The only way to do that is for the property's type to be known at compile time, either within this method definition, or for the caller. If the caller of this method knows what the type of the property is, then it can specify it using a second generic argument:
static Func<TInstance, TResult> CreateGetterDelegate<TInstance, TResult>(
PropertyInfo propertyInfo)
{
if (typeof(TInstance) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType);
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<TInstance, TResult>)Expression.Lambda(convert, instance)
.Compile();
}
Of course, this is just pushing the problem back to the caller. If even the caller isn't going to know what the type of the property is, then they have the exact same problem.
At the end of the day to avoid the boxing some code somewhere needs to know at compile time what the type of this property is. If someone, somewhere, will know at compile time, then you can just keep punting on solving the problem by using generics until you get to that point where someone can just use the actual known type. If nothing ever does know the type at compile time, then there really isn't any solution to this problem.
You could possibly, if you want to get technical, avoid boxing by making things even more dynamic than they are (using reflection to call these methods that are using reflection to do stuff) but while you may, from a technical standpoint, be able to avoid the literal box
command, you'd be losing out way more than you'd gained. It wouldn't be a practical solution.