【发布时间】:2010-11-04 16:12:45
【问题描述】:
我们需要在运行时评估对象中的值,同时我们有确切成员路径的文本语句,例如:myobject.firstMember.secondMember[3].text
我们想过使用正则表达式解析这个文本语句,然后使用反射评估文本值,但在我们这样做之前,我想知道 C# 是否支持某种 eval 能力?所以我们不必自己进行解析。微软如何在他们的即时窗口或监视窗口中执行此操作?
非常感谢,
阿迪·巴尔达
【问题讨论】:
我们需要在运行时评估对象中的值,同时我们有确切成员路径的文本语句,例如:myobject.firstMember.secondMember[3].text
我们想过使用正则表达式解析这个文本语句,然后使用反射评估文本值,但在我们这样做之前,我想知道 C# 是否支持某种 eval 能力?所以我们不必自己进行解析。微软如何在他们的即时窗口或监视窗口中执行此操作?
非常感谢,
阿迪·巴尔达
【问题讨论】:
可能最简单的方法是使用 System.Web.UI 中的DataBinder.Eval:
var foo = new Foo() { Bar = new Bar() { Value = "Value" } };
var value = DataBinder.Eval(foo, "Bar.Value");
【讨论】:
我编写了一个开源项目Dynamic Expresso,它可以将使用 C# 语法编写的文本表达式转换为委托(或表达式树)。表达式被解析并转换为Expression Trees,而不使用编译或反射。
你可以这样写:
var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
或
var interpreter = new Interpreter()
.SetVariable("service", new ServiceExample());
string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()";
Lambda parsedExpression = interpreter.Parse(expression,
new Parameter("x", typeof(int)));
parsedExpression.Invoke(5);
我的作品基于 Scott Gu 的文章http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx。
【讨论】:
在未来(大约在 5.0 时间范围内),“编译器即服务”或许能够做到这一点。实际上,你现在可以用“mono”做很多事情(见CsharpRepl和Mono.CSharp——但是,我希望它需要更多地了解上下文才能使用局部变量等Evaluate) - 但在当前的 MS .NET 产品中对此没有任何支持。
现在,您必须执行许多数据绑定代码所做的事情……用诸如“.”之类的标记将其分开。并使用反射。严格来说,绑定代码其实是使用TypeDescriptor/PropertyDescriptor而不是直接反射,但是效果是一样的。
【讨论】:
虽然是一种重量级的方法,但您可以使用 C# CodeDom 发出一个新的新程序集,其中包含仅使用该行代码的方法。
我承认,这比其他一些建议更加繁重,但另一方面,您让 C# 解析器完成繁重的工作,因此它应该能够处理您扔给它的所有内容它是有效的 C#。
如果你走这条路,你还需要确保你可以再次卸载发出的程序集,因此可能需要创建和卸载 AppDomain。
我已经成功实现并使用了上述技术。另一方面,如果您可以使用DynamicMethod,它的重量会轻得多。但是,我从未尝试过这种方法,所以我不能说您是否可以使用 C# 文字来实现 DynamicMethod 的主体。
【讨论】:
实际上,Windows Workflow Foundation 的表达式求值和规则引擎功能可以做这样的事情。见Introduction to the Windows Workflow Foundation Rules Engine。
这些组件的一个有趣之处在于,它们的设计目的是让您可以在自己的应用程序中托管设计时组件,以设计在您自己的自定义类的上下文中运行的规则和/或表达式集。例如,您会告诉它针对“myObject”设计一个表达式,它会知道有一个 firstMember 有一个 secondMember,它有一个索引器产生一个具有 text 属性的类型。您可以将表达式和规则保存为 XML,并在运行时将它们读回,而无需在运行时使用设计器。
【讨论】:
不幸的是,C# 没有任何本地工具可以完全按照您的要求进行操作。
但是,我的 C# eval 程序确实允许评估 C# 代码。它提供了在运行时评估 C# 代码并支持许多 C# 语句,包括像“myobject.firstMember.secondMember[3].text”这样的表达式。事实上,此代码可用于任何 .NET 项目,但仅限于使用 C# 语法。请访问我的网站http://csharp-eval.com,了解更多详情。
【讨论】:
您可以随时尝试我的轻量级 C# Eval 程序。它将 C# 语言的大部分子集编译为动态方法。我的 GitHub 存储库的完整详细信息 DavidWynne/CSharpEval
【讨论】:
AFAIK 没有这样的内置 Eval 函数。您必须采用 Regex+Reflection 的方式。我也认为 Visual Studio 也在做同样的事情。
【讨论】:
这是我用来查找动态嵌套属性的类似内容..您需要为索引器添加逻辑...以及一些额外的检查...我在调用方法中捕获空值/错误...
public static object FindDottedProperty(this object input, string propertyName) { 如果(输入==空) 返回空值; if (string.IsNullOrEmpty(propertyName)) 返回空值; 队列道具 = new Queue(propertyName.Split('.')); if (props.Count == 0) 返回空值; //从输入对象开始并从那里推出属性堆栈。 对象 ret = 输入; while (props.Count > 0) { var prop = props.Dequeue(); if (string.IsNullOrEmpty(prop)) 返回空值; /*** 在此处添加索引器逻辑 ***/ //根据当前命名项获取属性值 ret = ret.GetType().GetProperty(prop).GetValue(ret, null); if (null.Equals(ret)) 返回空值; } //返回查找的值 返回 ret; }【讨论】: