c# – 我可以将一个局部变量作为常量而不是闭包引用捕获到一个LINQ表达式中吗?

我想说

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

并将x捕获为常量,而不是变量引用。这个想法是,x将永远不会改变,所以当表达式稍后被编译时,编译器可以做常量折叠并产生更有效的代码 – 即,通过将指针解引入闭包记录来计算x / y一次而不是每次调用。

没有办法在方法中将x标记为只读,编译器不够聪明,不能检测到在创建表达式之后它不会更改。

我不喜欢手工制作表情。有什么辉煌的想法?

更新:我最终使用了奇妙的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);
        }
    }
}
C#中没有办法做到这一点。编译器不支持通过value / const捕获变量。也不能以这种方式在运行时将非const值转换为const值。

另外,C#编译器只有在已知常量值的初始编译期间才会执行常量折叠。如果可以将运行时的值冻结为常数,则它不会参与编译器常量折叠,因为它在运行时发生。

http://stackoverflow.com/questions/3991621/can-i-capture-a-local-variable-into-a-linq-expression-as-a-constant-rather-than

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c# – 我可以将一个局部变量作为常量而不是闭包引用捕获到一个LINQ表达式中吗?