Я бы хотел сказать
int x = magic(), y = moremagic();
return i => i + (x/y);
и x будет фиксироваться как константа вместо ссылки на переменные. Идея состоит в том, что x никогда не будет изменяться, и поэтому, когда выражение будет скомпилировано позже, компилятор может выполнять постоянную фальцовку и создавать более эффективный код, т.е. Вычислять x/y
один раз вместо каждого вызова, посредством разметки указателя в запись закрытия,
Невозможно пометить x как readonly внутри метода, а компилятор не достаточно умен, чтобы обнаружить, что он не изменяется после создания выражения.
Мне не хотелось бы создавать выражение вручную. Любые блестящие идеи?
UPDATE. Я закончил использование чудесного 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);
}
}
}