首先,我在.Net方面没有多少经验 - 尤其是在过去的7年里。
我正在尝试开发一个应用程序,并希望合并另一个库(https://github.com/Giorgi/Math-Expression-Evaluator)
该库允许我评估像Evaluate("a+b", a: 1,b: 1)
这样的数学表达式。方法签名为public decimal Evaluate(string expression, object argument = null)
我真的只是寻找文档和更多信息的指针..感谢您的一切。
编辑:对不起......故意留下它广泛,因为我不是在寻找人为我做的工作......我似乎无法找到自己研究的起点。
该方法称为
dynamic engine = new ExpressionEvaluator() ;
engine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6)) ;
在Evalute()的主体中是这段代码(它将该参数转换为字符串字典,十进制对。
if (argument == null)
{
return new Dictionary<string, decimal>();
}
var argumentType = argument.GetType();
var properties = argumentType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead && IsNumeric(p.PropertyType));
var arguments = properties.ToDictionary(property => property.Name,
property => Convert.ToDecimal(property.GetValue(argument, null)));
return arguments;
我希望能够解析的字符串类似于&#34; a:1,b:2&#34;并将其转换为与Evaluate()
签名匹配的对象。
答案 0 :(得分:11)
该库正在使用高级魔法......非常高级: - )
诀窍是该类声明为:
public class ExpressionEvaluator : DynamicObject
因此,它是一个实现.NET 4.0中引入的dynamic
魔法的类
现在......在课堂上有两种Evaluate
方法:
public decimal Evaluate(string expression, object argument = null)
和
private decimal Evaluate(string expression, Dictionary<string, decimal> arguments)
通常可见且可用的唯一方法是第一种方法。它用作:
engine.Evaluate("a + b + c", new { a = 1, b = 2, c = 3 });
new { ... }
创建一个匿名对象,然后通过使用反射Dictionary<string, decimal>
将其“解压缩”here,将其输入private Evaluate()
。
如果您尝试使用其他表示法,请使用:
engine.Evaluate("a + b + c", a: 1, b: 2, c: 3 });
然后.NET无法将该方法与存在的public Evaluate()
匹配,但是作为DynamicObject
的子类的类会导致C#编译器编写一些“魔术”代码,启动this方法(仍然由ExpressionEvaluator实现):
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
首先检查我们要调用Evaluate:
if (nameof(Evaluate) != binder.Name)
如果我们尝试调用Evaluate,则会将参数解压缩到new Dictionary<string, decimal>()
,然后调用private Evaluate()
。
作为旁注,要使用“动态”写作方式Evaluate
,您必须声明engine
变量;
dynamic dynamicEngine = new ExpressionEvaluator();
所以使用dynamic
变量类型。
现在......在编写库时,您可以:
使用匿名对象,问题是匿名对象必须在编译时定义其“形状”(因此在编译时您必须知道需要a
,{{1如果你没有在编译时创建b
,那么在运行时不需要c
。}和d
。例如,请参阅我在三年前提供的关于如何在运行时创建动态匿名类型的response。我为该代码块提供的原因之一是:
.NET框架的某些部分大量使用反射来渲染对象(例如所有各种数据网格)。这些部分与动态对象不兼容,通常不支持object []。解决方案通常是将数据封装在DataTable中......或者您可以使用: - )
请注意,在该回复的其中一条评论中,有一个链接指向由Dynamic.Linq的众多实现之一使用的代码的修改版本。
使用非匿名对象(new { a, b, c, d }
)。该库不区分匿名和非匿名对象。与以前一样的限制,因为在编译时你需要一个具有正确参数数量的new Foo { a = 1, b = 2 c = 3 }
类
使用Foo
表示法。可悲的是,即使这是非常静态的。您无法轻松添加新参数,必须在编译时定义“变量”的数量和名称。
一种可能的解决方案是修改源代码(它是单个文件)并使dynamic
这个方法:
public
然后您可以轻松动态地填充private decimal Evaluate(string expression, Dictionary<string, decimal> arguments)