C# Expression.Compile中捕获的内容

C# Expression.Compile中捕获的内容,c#,lambda,expression,expression-trees,C#,Lambda,Expression,Expression Trees,假设我得到了一个带有属性栏的Foo类型的类 我得到了以下方法: public static void DumpValue<T>(Expression<Func<T>> expr) { MemberExpression memberExpression = expression.Body as MemberExpression; Debug.WriteLine("{0} => {1}", memberExpression.Member.

假设我得到了一个带有属性栏的Foo类型的类

我得到了以下方法:

public static void DumpValue<T>(Expression<Func<T>> expr)
{
     MemberExpression memberExpression = expression.Body as MemberExpression;
     Debug.WriteLine("{0} => {1}", memberExpression.Member.Name, expr.Compile()());
}
它给出了输出:

Bar => Hello
Bar => World
我这里的问题涉及连续编译调用。重做Func足够聪明吗 例如Func(内部),这样实例就被删除了,这样它就可以用于Foo的任何实例,并且只有生成的委托是instancespecific?或者它确实为每个实例编译了完整的

如果是后者,我是否需要担心大量编译函数会污染内存,我看不到测试的任何影响

我知道这可以通过重写DumpValue来避免,但我想知道幕后发生了什么。这只是一个例子来说明

我在树林里挖了一条路,但找不到任何线索

重新表述这个问题: 编译器是否优化了实例并在此处缓存了一些信息,并且只将实例烘焙到最后一个委托中,还是“一直”执行

我这里的问题是关于编译。返工够聪明吗 将Func转换为类似Func的内容,以便删除实例 所以它可以用于任何Foo实例?还是真的要编译 每种情况都是这样吗

编译表达式时,会得到一个委托。如果要在调用编译后的表达式时使用任意实例,则不需要
表达式
,而需要
表达式

否则,您需要从头开始构建表达式树,以避免在表达式体中使用捕获的引用

关于缓存的事情。。。 我修改了您的代码,以检查即使编译两次相同的表达式树,也会得到不同的委托实例:

using System;
using System.Linq.Expressions;

public class Program
{
    public static Delegate DumpValue<T>(Expression<Func<T>> expr)
    {
        MemberExpression memberExpression = expr.Body as MemberExpression;

        return expr.Compile();
    }

    public static void Main()
    {
        string a = "foo";
        string b = "bar";

        var del1 = DumpValue(() => a);
        var del2 = DumpValue(() => b);

        // FALSE
        Console.WriteLine(Object.ReferenceEquals(del1, del2));
    }
}
使用系统;
使用System.Linq.Expressions;
公共课程
{
公共静态委托转储值(表达式expr)
{
MemberExpression MemberExpression=expr.Body作为MemberExpression;
返回expr.Compile();
}
公共静态void Main()
{
字符串a=“foo”;
字符串b=“bar”;
var del1=转储值(()=>a);
var del2=转储值(()=>b);
//假的
WriteLine(Object.ReferenceEquals(del1,del2));
}
}

简言之,没有缓存,正如我的回答从一开始就指出的,我怀疑这样的功能是否容易实现,因为它可能是非常用例和边缘情况,在这些情况下,泛化表达式可能是一项耗时的任务可能在大多数情况下,许多委托实例都比实现缓存算法(甚至在编译它们之前实现表达式树转换…)要好。

我要说的是,任何东西都没有缓存


电话。从那里创建一个新的实例,该实例初始化字段(使用
var方法=新的DynamicMethod(lambda.Name??“lambda_方法”,lambda.ReturnType,parameterTypes,true);
),然后使用该字段首先创建方法,然后创建委托。请注意,
\u方法
是只读的,因此任何人都不能更改它,它直接用于创建委托。任何地方都没有缓存。

.compile()
的每次调用都是compile new
DynamicMethod
。每个“compiled”
表达式都连接到
Foo
的不同实例(
a
b
)这并不能真正回答我的问题。我知道我可以重写这个表达式。我尝试重新表述我的问题,以便更清楚地知道编译器是否在幕后优化了实例。@CSharpie它确实回答了您的问题,但我刚刚在我的答案中添加了背景,以使其不回答否;)没有优化。表达式树类似于抽象语法树,但处于更高级的编译阶段。这就像在运行时构建C#代码而不进行解析。如果一个表达式访问一个引用,它将使用该引用,你不能更改它。我确信你在这里太快了。看到这个@CSharpie了吗?这不是私人/内部的吗\@CSharpie关于你的最新问题,我们应该期待Eric Lippert的回答,不是吗?
using System;
using System.Linq.Expressions;

public class Program
{
    public static Delegate DumpValue<T>(Expression<Func<T>> expr)
    {
        MemberExpression memberExpression = expr.Body as MemberExpression;

        return expr.Compile();
    }

    public static void Main()
    {
        string a = "foo";
        string b = "bar";

        var del1 = DumpValue(() => a);
        var del2 = DumpValue(() => b);

        // FALSE
        Console.WriteLine(Object.ReferenceEquals(del1, del2));
    }
}