Я бы хотел сказать
int x = magic(), y = moremagic();
return i => i + (x/y);
и сделать так, чтобы x был зафиксирован как константа вместо ссылки на переменную.Идея состоит в том, что x никогда не изменится, и поэтому, когда выражение будет скомпилировано позже, компилятор может выполнять свертывание констант и производить более эффективный код - то есть вычислять x/y
один раз вместо каждого вызова с помощью разыменования указателя в записи закрытия.,
Нет способа пометить x как метод readonly в методе, и компилятор не настолько умен, чтобы обнаружить, что он не изменяется после создания выражения.
Я быНенавижу строить выражения вручную.Какие-нибудь блестящие идеи?
ОБНОВЛЕНИЕ : я закончил тем, что использовал изумительный LinqKit для создания частичного оценщика, который будет выполнять замены, которые я хочу.Преобразование безопасно только в том случае, если вы знаете, что соответствующие ссылки не изменятся, но это сработало для моих целей.Частичную оценку можно ограничить только непосредственными членами вашего замыкания, которым вы управляете, добавив туда дополнительную проверку или две, что довольно очевидно при проверке примера кода, предоставленного в LinqKit.
/// <summary>Walks your expression and eagerly evaluates property/field members and substitutes them with constants.
/// You must be sure this is semantically correct, by ensuring those fields (e.g. references to captured variables in your closure)
/// will never change, but it allows the expression to be compiled more efficiently by turning constant numbers into true constants,
/// which the compiler can fold.</summary>
public class PartiallyEvaluateMemberExpressionsVisitor : ExpressionVisitor
{
protected override Expression VisitMemberAccess(MemberExpression m)
{
Expression exp = this.Visit(m.Expression);
if (exp == null || exp is ConstantExpression) // null=static member
{
object @object = exp == null ? null : ((ConstantExpression)exp).Value;
object value = null; Type type = null;
if (m.Member is FieldInfo)
{
FieldInfo fi = (FieldInfo)m.Member;
value = fi.GetValue(@object);
type = fi.FieldType;
}
else if (m.Member is PropertyInfo)
{
PropertyInfo pi = (PropertyInfo)m.Member;
if (pi.GetIndexParameters().Length != 0)
throw new ArgumentException("cannot eliminate closure references to indexed properties");
value = pi.GetValue(@object, null);
type = pi.PropertyType;
}
return Expression.Constant(value, type);
}
else // otherwise just pass it through
{
return Expression.MakeMemberAccess(exp, m.Member);
}
}
}