C# Expression.Compile中捕获的内容
假设我得到了一个带有属性栏的Foo类型的类 我得到了以下方法: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.
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 newDynamicMethod
。每个“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));
}
}