A concise compiler
I have repeatedly seen the calculation problem of the text expression, and I will handle the previous code and add a comment.
Write a simple compiler is not very complicated, and you should use some reflection knowledge. Since it feels that the use of reflection is really ubiquitous in NET, and there is no efficiency of the use of reflection. After all, the current computer configuration is not very low. Appropriate use of reflections, or by using reflex itself, you will deepen your understanding of NET. In the future, you will write a small "article" for the use of reflection to increase the flexibility.
If only the value of the expression is calculated, there is of course so many code. This way to write, just make it versatile.
I put the code directly below, no longer say something (can say how to be stinky, just don't want to recruise).
Imports system.reflection
Imports system.codedom
Imports system.codedom.compiler
Public Class SourceComp
'// Compiler interface
Private m_compiler as icodecompiler
'// Compiler parameters
Private M_CompilerParameters as CompilerParameters
'// quoted assembly
Private m_refassemblies as string () = {"system.dll", "system.data.dll"}
'// source code
Private M_Source As String = ""
'// Record is the default source code
Private m_is_default as boolean = TRUE
'// Record the compilation status
PRIVATE M_Compiled as boolean = false
'// Compile the generated assembly
Private m_assembly as system.reflection.Assembly
'// The instance of the default source code generated
Private m_tmpclass as object
'// Default source code generated instance function
Private m_methodinfo as system.reflection.MethodInfo
'// Default source code function expression parameters
Private M_Expression As String
'// Return to the assembly
Public Readonly Property CPassembly () as system.reflection.Assembly
Get
Return me.m_assemblyMbly
END GET
End Property
Sub new ()
'// Get the VB compiler instance
Me.m_compiler = new vbcodeProvider (). CreateCompiler
'// initial compiler parameters
Me.m_compilerParameters = New CompilerParameters
With me.m_compilerparameters
.Generateexecutable = false '// false value specifies compiled as class set, True compiles to executable
.GenerateInMemory = false '// only generate an assembly in memory, not output to disk
'// Add a default assembly
Me.Add_compilerParameters ()
End with
End Sub
'// Add assembly to reference
Private sub add_compilerparameters ()
Me.m_compilerParameters.referenceDassemblies.addrange (me.m_refassemblies)
End Sub
'// Add a specified reference assembly
Public Sub Add_compilerParameters (BYVAL REFASSEMBLIES AS STRING ())
Me.m_refassemblies = Refassemblies
Me.m_compilerParameters.referenceDassemblies.clear () '// Clear the original assembly, repeat reference compilation will result in an exception
Me.Add_compilerParameters ()
End Sub
'// Generate a default source code
'// Category Name: TMPCLASS
'// Function Name: getExpressionValue, Parameters: Expression, Parameter Type: String
'// Main function: return the value of Expression Expression, return value type: Object
Private suildDefaultsource ()
Dim Mcodebuilder As CodeBuilder = New CodeBuilder
With mcodebuilder
.Appendcode ("imports system")
.Appendcode ("Imports System.Data)
.Appendcode ("Imports System.math")
.Appendcode ("Imports Microsoft.visualBasic")
.Appendcode ()
.Appendcode ("Public Class TmpClass")
.Appendcode ("Public Function GetExpressionValue () As Object")
.Appendcode ("Dim Result As Object")
.Appendcode ("Result = {0}") 'here incoming expressions
.Appendcode ("Return Result")
.Appendcode ("end function")
.Appendcode ("End Class")
End with
Me.m_source = mcodebuilder.tostring
End Sub
'// Specify source code
Public SUB STSource (Byval Source As String)
Me.m_source = SOURCE
Me.m_compiled = false
Me.m_is_default = false
End Sub
'// Read source code from the specified file
Public Sub getSourceFile (Byval SourceFileName As String)
Dim Mcodebuilder As CodeBuilder = New CodeBuilder
McodeBuilder.Appendfromfile (SourceFileName)
Me.m_source = mcodebuilder.tostring
Me.m_compiled = false
Me.m_is_default = false
End Sub
'// Compile
Public Sub Complile ()
If me.m_source = "" "
Me.builddefaultsource ()
END IF
If me.m_is_default then
'Incoming parameters
Me.m_source = String.Format (me.m_source, me.m_expression)
END IF
DIM MCompResult As CompilerResults = me.m_compiler.compileassemblyFromSource (me.m_compilerparameters, me.m_source)
'//Error message
IF (mcompResult.errors.haserror) THEN
Dim ErrorMessage As String
ErrorMessage = "Compile error:" & vbcrlf
Dim Err As CompileRrror
For Each Err in MCompResult.errors
ErrorMessage = ErrorMessage & Err.ErrorText & Vbcrlf
NEXT
Throw New Exception ("Compiling Error:" ErrorMessage)
END IF
Me.m_assembly = mcompResult.compiledassembly
ME.m_compiled = TRUE
End Sub
'// If it is the default source code, this function takes the value of the expression;
'// If you customize the source code, please refer to this function to write it yourself.
Public Function GetExpressionValue (Byval Expression As String) AS Object
IF not me.m_is_default the
Msgbox ("The code used is not the default code, this function is invalid")
Return Nothing
END IF
'If you have not compiled, compile
IF not me.m_compiled
'// Parameter expression as a code
Me.m_expression = expression
COMPLILE ()
'// Generate an instance, pay attention to the class name
Me.m_tmpclass = me.m_assembly.createInstance ("TMPCLASS")
'// Take a function, pay attention to the case
m_methodInfo = me.m_tmpclass.gettype (). getMethod ("getExpressionValue")
END IF
'//Calculation results
Dim Result As Object = m_methodinfo.invoke (m_tmpclass, nothing)
'The expression is different when it is different.
Me.m_compiled = false
Return RESULT
END FUNCTION
END CLASS
'// format the class to generate or read the code
Public Class CodeBuilder
Private _stringbuilder as system.text.stringbuilder
'// format, {0} is the number of spaces, {1} code strings, finally add to the train
Private const codeformat as string = "{0} {1}" & controlchars.crlf
Sub new ()
_StringBuilder = new system.text.stringbuilder
End Sub
Public overloads sub appendcode ()
_StringBuilder.AppendFormat (CodeFormat, Space (0), Space (0))
End Sub
Public overloads sub appendcode (Byval CodeString As String) _StringBuilder.AppendFormat (CodeFormat, Space (0), CODEString)
End Sub
Public overloads sub appendcode (byval codefloor as integer, Byval Codestring as string)
_StringBuilder.AppendFormat (CodeFormat, Space (Codefloor * 4), Codestring
End Sub
'// Directly read code from existing VB files
Public Sub appendfromfile (Byval FileName As String)
IF not system.io.file.exists (filename) THEN
MsgBox (FileName & "does not exist.")
EXIT SUB
END IF
DIM TMPSTR AS STRING
DIM FS as system.IO.FileStream
Fs = new system.io.filestream (filename, io.filemode.open, io.fileAccess.read, oosed)
Dim Reader As New System.io.StreamReader (fs, system.text.encoding.default)
TMPSTR = Reader.ReadToend
Reader.close ()
fs.close ()
_StringBuilder.Append (tmpstr)
End Sub
'// Return to the code string
Public overrides function toString () AS STRING
Return_stringbuilder.tostring
END FUNCTION
'// Clear the original code
Public Sub Clear ()
IF_StringBuilder.Length> 0 Then _stringbuilder.remove (0, _StringBuilder.Length - 1)
End Sub
End Class' CodeBuilder
'test
DIM MyComp as SourceComp
Private sub button1_click (byvale as system.object, byval e as system.eventargs) Handles Button1.click
'If you don't regenerate an instance, you will be wrong due to the temporary assembly of the same name when recompilated.
Mycomp = new sourceComp
Console.writeline (MyComp.GetexpressionValue ("Math.Round (Math.SQRT (123 * 456), 2)") .tostring)
'Result 236.83
Mycomp = new sourceComp
Console.writeline (MyComp.GetexpressionValue ("123 * 456> 12 * 6987"). TOSTRING)
'Result False
End Sub