Kann ich eine lokale Variable in einem LINQ-Ausdruck als Konstante statt als Abschlussreferenz erfassen?

Ich würde gerne sage

int x = magic(), y = moremagic();
return i => i + (x/y);

und das x muss als Konstante statt als Variablenreferenz erfasst werden. Die Idee ist, dass sich x niemals ändern wird. Wenn der Ausdruck später kompiliert wird, kann der Compiler konstant falten und effizienteren Code erzeugen - d. H. @ Berechnex/y einmal statt bei jedem Aufruf über Zeiger-Dereferenzen in einen Abschlussdatensatz.

Es gibt keine Möglichkeit, x innerhalb einer Methode als schreibgeschützt zu kennzeichnen, und der Compiler ist nicht clever genug, um festzustellen, dass er sich nach der Erstellung des Ausdrucks nicht ändert.

Ich würde es hassen, den Ausdruck von Hand bauen zu müssen. Irgendwelche genialen Ideen?

AKTUALISIERE: Ich endete mit dem wunderbaren LinqKit, um einen Teilauswerter zu erstellen, der die gewünschten Substitutionen ausführt. Die Transformation ist nur dann sicher, wenn Sie wissen, dass sich relevante Referenzen nicht ändern, sie hat jedoch für meine Zwecke funktioniert. Es ist möglich, die Teilbewertung nur auf direkte Mitglieder Ihres Abschlusses zu beschränken, die Sie steuern, indem Sie ein oder zwei zusätzliche Häkchen hinzufügen, was bei der Überprüfung des im LinqKit bereitgestellten Beispielcodes ziemlich offensichtlich ist.

/// <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);
        }
    }
}

Antworten auf die Frage(10)

Ihre Antwort auf die Frage