tags:

views:

87

answers:

2

First the requirements:

  • By management requirements, I can't use open source code.
  • I need the users to define their own formulas for a project.
  • My users don't know how to code.
  • The formulas need to be saved somehow, and being read later.
  • I need to debug the formulas written, so I need to be able to see and understand them.
  • The formulas used are quite specialized and specific (actuarial formulas).
  • Adding new formulas (functionality) must be done in fast and maintainable way.

What I did?

I implemented an abstract class let's say FormulaBase that all formulas inherit from:

Public MustInherit Class FormulaBase
    Public MustInherit Function Formula(ByVal p as Parameters) as Result
    Public MustInherit Function GetXML() as Text.StringBuilder
End Class

Then I created classes that wrapped the formulas like this:

Public Class SumFormula
    Inherits FormulaBase

    Public Shared ReadOnly Property XMLTag() As String
        Get
            Return "sum"
        End Get
    End Property

    Private X As FormulaBase
    Private Y As FormulaBase

    Public Sub New(ByVal xmlText as Xml.XmlNode)
        ' Code to obtain read the sum parameters form XML.'
    End Sub

    Public Overrides Function Formula(ByVal p as Parameters) as Result
        Return X.Formula(p) + Y.Formula(p)
    End Function

    Public Override Function GetXml() as Text.StringBuilder
        Return New Text.StringBuilder().Append("<sum>").Append(X.GetXml()).Append(Y.GetXml()).Append("</sum>")
    End Function
End Class

Then I created a factory to construct the formulas, like this:

Public NotInheritable Class FormulaFactory
    Private Shared Formulas As Dictionary(Of String, Reflection.ConstructorInfo) = InitializeFormulas()

    Private Shared Sub Add(ByVal collection As Dictionary(Of String, Reflection.ConstructorInfo), ByVal formula as Type)
        ' Some code to extract the contructor and XmlTag from each class and add them to the dictionary.'
    End Sub

    Private Shared Function InitializeFormulas() As Dictionary(Of String, Reflection.ConstructorInfo)
        Dim Collection As New Dictionary(Of String, Reflection.ConstructorInfo)
        Add(Collection, GetType(SumFormula))
        Return Collection
    End Sub

    Public Shared Function ConstructFormula(xmlText as Xml.XmlNode) as FormulaBase
        Return DirectCast(Formulas(xmlText).Invoke(New Object(){xmlText}), FormulaBase)
    End Function
End Class

I use some more magic to showthe formulas to the users so they won't see the XML. To add anew formula i just need to create the wrapper class, add a Shared XMLTag property and a constructor that takes a XMLNode as parameter. Then I add a line to the FormulaFactory.InitializeFormulas method.

The question is, ¿Is there some other way I could have gone?

+1  A: 

Another option might have been to use something like PublicDomain's dynamic code evaluation.

This could allow the "snippet" to be just read in and dynamically parsed at runtime. Plugging in formulas via a GUI and saving them, loading them, and evaluating them would be fairly easy in this case.

Reed Copsey
I'll check it, but I can't use open source. :'(I've added the limitation to the requirements.
Wilhelm
Didn't read the license. Its public domain, duh!
Wilhelm
+1  A: 

The Rules Engine of Windows Workflow Foundation was designed to be usable outside of Visual Studio, and in fact, outside of the context of workflow. Part of it is an expression editor, which can even be used outside of the context of the rules engine.

See External RuleSet Toolkit Sample and Introduction to the Windows Workflow Foundation Rules Engine.

John Saunders