【发布时间】:2018-07-31 00:06:50
【问题描述】:
给定这个类
public class Foo
{
public string Name { get; set; }
}
这个方法(在其他类中)...
private Func<Foo, string> Compile(string body)
{
ParameterExpression prm = Expression.Parameter(typeof(Foo), "foo");
LambdaExpression exp = DynamicExpressionParser.ParseLambda(new[] { prm }, typeof(string), body);
return (Func<Foo, string>)exp.Compile();
}
将取 lambda 表达式的右侧并给我一个委托。所以如果它是这样调用的:
Foo f = new Foo { Name = "Hamilton Academicals" };
//foo => foo.Name.Substring(0,3)
Func<Foo, string> fn = Compile("foo.Name.Substring(0,3)");
string sub = fn(f);
那么 sub 的值将是“Ham”。
一切都很好,但是,我想让 Foo 成为 DynamicObject 的子类(这样我就可以实现 TryGetMember 来动态计算出属性值),所以我想采用表达式并获得等价的 this
Func<dynamic, dynamic> fn = foo => foo.Name.Substring(0,3);
我已经尝试使用自定义CallSiteBinder 使用Expression.Dynamic,但是由于类型Bar 中不存在Bar (当我尝试动态访问foo.Bar 时)而失败。我假设这是因为获取foo.Bar 的调用需要动态调度(使用Expression.Dynamic),但这对我不起作用,因为一个关键目标是用户可以输入一个简单的表达式和让它执行。有可能吗?
【问题讨论】:
-
为此,我假设您需要另一个专门处理动态表达式的解析器。这个是行不通的。也许只是使用成熟的编译器(Roslyn)?预期的表达式有多复杂?
-
@Evk - 是的。在我发布后,我得出了同样的结论。表达式将很简单(一个衬里)。无法使用 Roslyn,因为生成的程序集不符合垃圾回收条件。
-
您可以将生成的程序集加载到单独的应用程序域中并拆除它们。当然,这会影响性能,通常不是很好的解决方案,但总比没有好,具体取决于您对性能的要求。
-
True... 除非我想以 .NET Core 为目标
-
好吧,那么我认为你很不走运,至少在他们在 .NET Core 中实现 dll 卸载之前(据我所知,这是即将推出的功能)。实现您自己的使用动态表达式的解析器可能并非易事。