Sample working code to show dynamic execution of VB.NET code that can be used to externalize the rules.
Dynamic Code Execution in VB.Net: A very useful tool to externalize the Rules
File: Module1.vb to test and run the Code
Module Module1
Sub Main()
Dim cCheck As New CodeCreate
Dim CarType As String = "CAR"
Dim CarMake As String = "TOYOTA"
Dynamic Code Execution in VB.Net : A very useful tool to externalize the Rules
File: Module1.vb to test and run the Code
Module Module1
Sub Main()
Dim cCheck As New CodeCreate
Dim CarType As String = "CAR"
Dim CarMake As String = "TOYOTA"
Dim CarYear As String = "2010"
Dim CarMile As String = "100010"
System.Console.WriteLine("Depreciation Rate of {1} {0} of YEAR {2} WITH {3} miles: {4}%", _
CarType, CarMake, CarYear, CarMile, cCheck.GetDeprecRate(CarType, CarMake, CarYear,
CarMile))
System.Console.ReadKey()
End Sub
End Module
File: IScript.vb (Interface)
'interface to generate script
Public Interface IScript
Function CheckCar(carMake As String, CarYear As String, Miles As String) As Integer
End Interface
File: CodeCreate.vb
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Text
Public Class CodeCreate
'' function that defines vb compiler environment and reference assemblies
Private Function GenerateScript(code As String) As IScript
Using provider As New VBCodeProvider()
Dim parameters As New CompilerParameters()
parameters.GenerateInMemory = True
parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
parameters.ReferencedAssemblies.Add("System.dll")
parameters.ReferencedAssemblies.Add("System.Data.dll")
parameters.ReferencedAssemblies.Add("System.Xml.dll")
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)
If results.Errors.HasErrors Then
Throw New Exception("Failed to compile script")
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
End Using
End Function
'' create script
Private Function createScript(myscript As String) As IScript
Dim builder As New StringBuilder()
builder.AppendLine("Public Class Script")
builder.AppendLine(" Implements IScript")
builder.AppendLine(" Public Function CheckCar(carMake As String, CarYear As String, Miles As String) As
Integer Implements IScript.CheckCar")
builder.AppendLine(" dim retVal as integer = 60")
builder.AppendLine(myscript)
builder.AppendLine(" return retVal")
builder.AppendLine(" End Function")
builder.AppendLine("End Class")
Dim script As IScript = GenerateScript(builder.ToString())
Return script
End Function
'-- get the script
Private Function GetScript() As IScript
Dim ruleString As New List(Of String)
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR<2010 AND (MILES/1000) <=10 THEN RETURN 20")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2010 AND (MILES/1000) <=10 THEN RETURN 10")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2011 AND (MILES/1000) <=10 THEN RETURN 9")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2012 AND (MILES/1000) <=10 THEN RETURN 8")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2013 AND (MILES/1000) <=10 THEN RETURN 7")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2014 AND (MILES/1000) <=10 THEN RETURN 6")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR>=2014 AND (MILES/1000) <=10 THEN RETURN 5")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR<2010 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 30")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2010 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 25")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2011 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 20")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2012 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 17")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2013 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 15")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2014 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 12")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR>=2014 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 10")
'--- more rules can be loaded from database
'-- and the rules can be separated into the classes for each type of vehicle
'-- with the use of OOP's polymorphism (Implementing Strategy Pattern)
Dim allRules As New StringBuilder
ruleString.ForEach(Sub(x) allRules.AppendLine("IF " & x))
Return createScript(allRules.ToString)
End Function
'' function to return depreciation
Public Function GetDeprecRate(CarType As String, carMake As String, CarYear As String, Miles As String) As
String
Dim ms As New CodeCreate()
Dim scriptEXEC As IScript = ms.GetScript()
If CarType = "CAR" Then
Return (scriptEXEC.CheckCar(carMake, CarYear, Miles)).ToString
End If
Return "UNKNOWN!"
End Function
End Class
Dim CarYear As String = "2010"
Dim CarMile As String = "100010"
System.Console.WriteLine("Depreciation Rate of {1} {0} of YEAR {2} WITH {3} miles: {4}%", _
CarType, CarMake, CarYear, CarMile, cCheck.GetDeprecRate(CarType, CarMake, CarYear,
CarMile))
System.Console.ReadKey()
End Sub
End Module
File: IScript.vb (Interface)
'interface to generate script
Public Interface IScript
Function CheckCar(carMake As String, CarYear As String, Miles As String) As Integer
End Interface
File: CodeCreate.vb
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Text
Public Class CodeCreate
'' function that defines vb compiler environment and reference assemblies
Private Function GenerateScript(code As String) As IScript
Using provider As New VBCodeProvider()
Dim parameters As New CompilerParameters()
parameters.GenerateInMemory = True
parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
parameters.ReferencedAssemblies.Add("System.dll")
parameters.ReferencedAssemblies.Add("System.Data.dll")
parameters.ReferencedAssemblies.Add("System.Xml.dll")
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)
If results.Errors.HasErrors Then
Throw New Exception("Failed to compile script")
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
End Using
End Function
'' create script
Private Function createScript(myscript As String) As IScript
Dim builder As New StringBuilder()
builder.AppendLine("Public Class Script")
builder.AppendLine(" Implements IScript")
builder.AppendLine(" Public Function CheckCar(carMake As String, CarYear As String, Miles As String) As
Integer Implements IScript.CheckCar")
builder.AppendLine(" dim retVal as integer = 60")
builder.AppendLine(myscript)
builder.AppendLine(" return retVal")
builder.AppendLine(" End Function")
builder.AppendLine("End Class")
Dim script As IScript = GenerateScript(builder.ToString())
Return script
End Function
'-- get the script
Private Function GetScript() As IScript
Dim ruleString As New List(Of String)
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR<2010 AND (MILES/1000) <=10 THEN RETURN 20")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2010 AND (MILES/1000) <=10 THEN RETURN 10")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2011 AND (MILES/1000) <=10 THEN RETURN 9")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2012 AND (MILES/1000) <=10 THEN RETURN 8")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2013 AND (MILES/1000) <=10 THEN RETURN 7")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2014 AND (MILES/1000) <=10 THEN RETURN 6")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR>=2014 AND (MILES/1000) <=10 THEN RETURN 5")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR<2010 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 30")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2010 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 25")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2011 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 20")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2012 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 17")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2013 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 15")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR=2014 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 12")
ruleString.Add("carMake=""TOYOTA"" AND CARYEAR>=2014 AND (MILES/1000) >10 and (MILES/1000)<20 THEN RETURN 10")
'--- more rules can be loaded from database
'-- and the rules can be separated into the classes for each type of vehicle
'-- with the use of OOP's polymorphism (Implementing Strategy Pattern)
Dim allRules As New StringBuilder
ruleString.ForEach(Sub(x) allRules.AppendLine("IF " & x))
Return createScript(allRules.ToString)
End Function
'' function to return depreciation
Public Function GetDeprecRate(CarType As String, carMake As String, CarYear As String, Miles As String) As
String
Dim ms As New CodeCreate()
Dim scriptEXEC As IScript = ms.GetScript()
If CarType = "CAR" Then
Return (scriptEXEC.CheckCar(carMake, CarYear, Miles)).ToString
End If
Return "UNKNOWN!"
End Function
End Class