首先,我在.Net方面经验不足,尤其是在过去的7年中。

我正在尝试开发应用程序,并希望合并另一个库(https://github.com/Giorgi/Math-Expression-Evaluator)

该库允许我评估诸如Evaluate("a+b", a: 1,b: 1)之类的数学表达式。方法签名为public decimal Evaluate(string expression, object argument = null)

  • 我想更好地了解.Net如何将逗号分隔的参数转换为单个“参数”。
  • 我不确定如何动态创建该参数。例如,遍历值列表并创建与该签名的适当参数匹配的对象。

  • 我真的只是在寻找文档和更多信息的指针。

    编辑:对不起..故意将其保留得很宽泛,因为我不是在找人为我做我的工作..似乎无法找到开展我自己的研究的起点。

    该方法称为
    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;
    

    我想做的是解析一个字符串,例如“a:1,b:2”,然后将其转换为与该Evaluate()签名匹配的对象。

    最佳答案

    那个图书馆正在使用高级魔法...非常高级:-)

    诀窍是将该类声明为:

    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>的反射将其“解包”给private Evaluate()来将其解压缩。

    如果尝试使用另一种表示法,则该表示法如下:
    engine.Evaluate("a + b + c", a: 1, b: 2, c: 3 });
    

    然后.NET无法将该方法与存在的public Evaluate()进行匹配,但是该类是DynamicObject的子类,导致C#编译器编写一些“魔术”代码来启动here方法(该表达式仍由ExpressionEvaluator实现) ):
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    

    首先检查我们要调用“评估”:
    if (nameof(Evaluate) != binder.Name)
    

    如果我们尝试调用Evaluate,它将参数解压缩为new Dictionary<string, decimal>(),然后调用private Evaluate()

    附带说明,要使用“动态”方式编写Evaluate,必须声明engine变量,例如;
    dynamic dynamicEngine = new ExpressionEvaluator();
    

    因此使用dynamic变量类型。

    现在...在编写库之后,您可以:
  • 使用匿名对象,这样的问题是,在编译时必须定义匿名对象的“形状”(因此,在编译时,您必须知道将需要abc。不需要d如果您未在编译时创建new { a, b, c, d },则在运行时)。例如,请参阅我三年前给出的this,它关于如何在运行时创建动态匿名类型。我给出该代码块的原因之一是:



    请注意,在对该响应的评论之一中,有一个指向我的代码的修改版本的链接,该链接由Dynamic.Linq的许多实现之一使用。
  • 使用非匿名对象(new Foo { a = 1, b = 2 c = 3 })。该库不区分匿名对象和非匿名对象。与以前一样的限制,因为在编译时,您需要一个带有正确数量的
  • 参数的Foo
  • 使用dynamic表示法。可悲的是,即使那是完全静态的。您不能轻易添加新参数,因为必须在编译时定义“变量”的数量和名称。

  • 一个可能的解决方案是修改源代码(它是一个文件),并使public成为此方法:
    private decimal Evaluate(string expression, Dictionary<string, decimal> arguments)
    

    那么您就可以轻松,动态地填充Dictionary<string, decimal> arguments

    关于c# - 在C#中动态创建数组的方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50722680/

    10-10 16:32