代码之家  ›  专栏  ›  技术社区  ›  Peter Morris

如何允许用户在C应用程序中定义财务公式

  •  1
  • Peter Morris  · 技术社区  · 16 年前

    我需要允许我的用户能够定义将根据数据计算值的公式。例如

    //Example 1
    return GetMonetaryAmountFromDatabase("Amount due") * 1.2;
    //Example 2
    return GetMonetaryAmountFromDatabase("Amount due") * GetFactorFromDatabase("Discount");
    

    我需要允许/*+-操作,也需要分配局部变量并执行if语句,就像这样

    var amountDue = GetMonetaryAmountFromDatabase("Amount due");
    if (amountDue > 100000) return amountDue * 0.75;
    if (amountDue > 50000) return amountDue * 0.9;
    return amountDue;
    

    场景很复杂,因为我有以下结构。

    1. 顾客(几百人)
    2. 配置(每个客户约10个)
    3. 项目(每个客户配置约10000个)

    所以我将执行一个三级循环。在每个“配置”级别,我将启动一个DB事务并编译forumlas,每个“项目”将使用相同的事务+已编译的公式(每个配置大约有20个公式,每个项目将使用所有公式)。

    这进一步使事情复杂化,因为我不能只使用编译器服务,因为它会导致内存使用量的持续增长。对于每个“配置”循环级别,我不能使用新的AppDomain,因为我需要传递的某些引用无法封送。

    有什么建议吗?

    --更新—— 这就是我要的,谢谢! http://www.codeproject.com/Articles/53611/Embedding-IronPython-in-a-C-Application

    5 回复  |  直到 11 年前
        1
  •  1
  •   Peter Morris    11 年前

    您可以在运行时创建一个简单的类,只需将逻辑写入一个字符串或类似的字符串,编译它,运行它并使它返回您需要的计算。本文向您展示了如何从运行时访问编译器: http://www.codeproject.com/KB/cs/codecompilation.aspx

        2
  •  2
  •   dviljoen    16 年前

    Iron Python 允许您将脚本引擎嵌入到应用程序中。还有很多其他的解决方案。事实上,你可以用谷歌搜索类似“C嵌入式脚本”的东西,然后找到一大堆选项。有些比其他的更容易集成,有些比其他的更容易编写脚本。

    当然,总会有vba。但那简直太难看了。

        3
  •  1
  •   Paul Shealy    16 年前

    几年前我也遇到过类似的问题。我有一个网络应用程序,流量适中,需要方程式,它需要类似于你的功能,而且速度必须快。我有几个想法。

    第一个解决方案是向数据库中添加计算列。我们的应用程序表将属性存储在列中(例如,有一列显示到期金额、另一个折扣等)。如果用户键入了类似propertya*2的公式,代码将更改基础表,使其具有新的计算列。在添加和删除列方面是混乱的。不过,它确实有一些优点:数据库(SQL Server)计算速度非常快;数据库为我们处理了大量错误检测;我可以假装计算值与非计算值相同,这意味着我不必修改任何使用非计算值的现有代码。路费。

    在我们需要一个公式引用另一个公式的能力之前,这是有效的,而SQL Server不允许这样做。所以我切换到一个脚本引擎。当时Ironpython还不是很成熟,所以我选择了另一个引擎…我现在不记得是哪一个了。总之,写起来很容易,但速度有点慢。不是很多,每个查询可能几毫秒,但是对于一个Web应用程序来说,所有请求的时间实际上都加起来了。

    当时我决定为公式编写自己的解析器。也就是说,我有一个plustoken类来添加两个值,一个对应getValue(“折扣”)的itemToken类,等等。当用户输入一个新的公式时,验证器解析该公式,确保它是有效的(例如,它们引用了一个不存在的列吗?)并将其存储在半编译的形式中,以便以后解析。当用户请求计算值时,解析器会读取公式并对其进行解析,从数据库中找出所需的数据,然后计算出最终的答案。前期做了大量的工作,但效果很好,而且速度很快。我学到了:

    1. 如果用户输入的公式导致公式中出现循环,而您试图计算公式的值,则堆栈空间将耗尽。如果您在Web应用程序上运行此程序,则整个Web服务器将停止工作,直到您重置它。所以在验证阶段检测循环是很重要的。
    2. 如果有多个公式,请将所有数据库调用聚合到一个位置,然后一次请求所有数据。快得多。
    3. 用户将把古怪的东西输入公式。一个提供有用错误消息的解析器稍后会节省很多麻烦。
        4
  •  1
  •   Ope    16 年前

    如果定制脚本没有比上面显示的脚本更复杂,那么我同意西尔维斯特的观点:创建自己的解析器,生成一个树,然后自己进行逻辑运算。您可以生成 .Net expression tree 或者自己浏览语法树,在自己的代码中进行操作(下面的antlr将帮助您生成这样的代码)。

    然后你就完全控制了你的引用,你总是在C之内,所以你不需要担心内存管理(比你通常做的更多)等。 Antlr 是在C中执行此操作的最佳工具。你可以从网站上获得一些小语言的例子,比如你的场景。

    但是…如果这真的只是一个开始,而到了最后,您几乎需要一种适当的脚本语言的全部功能,那么您需要将脚本语言嵌入到您的系统中。使用您的数字,您将遇到性能、内存管理和引用方面的问题。有几种方法,但我不能为您的场景给出一个建议:我从来没有这样做过。

        5
  •  0
  •   Sylvestre Equy    16 年前

    可以构建两个基类unaryOperator(if、square、root…)和binaryOperator(+-/*),并从表达式构建树。然后为每个项目评估树。