Introduction
With the code of this article, you will compile code without having Visual Studio .NET installed, and you will avoid using the tangled compiler command line. With this code, you can create your own compiling environment.
I try to explain in this article how to dynamically compile code in VB.NET or C# using CodeDom technology. This technology simplifies the automatic code generation and can be used like a new generation of script engine, because you can write any .NET code, compile, and execute it in a dynamic way.
Background
What is CodeDom?
CodeDom is Code Document Object Model. This provides a graphical (in the sense of graph nodes, not of a picture) representation of code in the form of a tree. This represents the hierarchy of nested code elements (namespaces contain classes, classes contain methods, methods contain variable declarations, and so on). You can use CodeDom for generating an in memory code tree, or you can use it to compile ordinary code written in a file (like we will do later). View MSDN to read all about CodeDom elements. With this code tree, you can represent any piece of code independently of a specific language.
Using the code
In this section, we will create a class named VBNetCompiler
. This class contains all the needed elements to compile Visual Basic .NET code files. I want to remember you that CodeDom is language-agnostic, and for this reason, you can easily create a CSharpCompiler or any compiler supported by CodeDom technology.
Imports section
Imports System.IO
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Collections.Specialized
Class and private members section
mFilesToCompile
: Collection that contains all source code files.
mImportedDlls
: Collection with all DLLs referenced by the code files.
mVBCompilerResults
: This is an object in the CodeDom
namespace to hold the output yielded by the compiler. This is similar to compiler output written in Output Pane of Visual Studio.
mVBCompilerErrors
: Error collection produced by the Compiler
mVBCompilerParameters
: This object is used to set the Compiler options
Public Class VBNetCompiler
Protected mFilesToCompile As New _
System.Collections.Specialized.StringCollection
Protected mImportedDlls As New StringCollection
Protected mVBCompilerResults As CompilerResults
Protected mVBCompilerErrors As CompilerErrorCollection
Protected mVBCompilerParameters As New CompilerParameters
Constructor and public properties
Public Sub New(ByVal ParamArray pFilesToCompile() As String)
mFilesToCompile = New System.Collections.Specialized.StringCollection
For Each oFile As String In pFilesToCompile
mFilesToCompile.Add(oFile)
Next
End Sub
Public Sub New()
End Sub
Public Property FilesToCompile() As _
System.Collections.Specialized.StringCollection
Get
Return mFilesToCompile
End Get
Set(ByVal Value As System.Collections.Specialized.StringCollection)
mFilesToCompile = Value
End Set
End Property
Public Property VBCompilerParameters() As CompilerParameters
Get
Return mVBCompilerParameters
End Get
Set(ByVal Value As CompilerParameters)
mVBCompilerParameters = Value
End Set
End Property
Public ReadOnly Property VBCompilerErrors() As CompilerErrorCollection
Get
Return mVBCompilerErrors
End Get
End Property
Public ReadOnly Property VBCompilerResults() As CompilerResults
Get
Return mVBCompilerResults
End Get
End Property
Public Property ImportedDlls() As StringCollection
Get
Return mImportedDlls
End Get
Set(ByVal Value As StringCollection)
mImportedDlls = Value
End Set
End Property
Compile function
This function is the core of the class. First, create a VBCodeProvider
, this object provides the code generator object and the code compiler (we will use this object to compile the code). In the line oVBCodeCompiler = oVBCodeProvider.CreateCompiler
, we create the code compiler. After creating the compiler, I assign the referenced assemblies needed for code compilation. Later, I add the files to compile, and call the method CompileAssemblyFromFileBatch
that compiles the code file array with the parameters specified by mVBCompilerParameters
object. The next lines write the compiler output to the Console
.
Public Function Compile() As CompilerResults
Dim oVBCodeProvider As New VBCodeProvider
Dim oVBCodeCompiler As ICodeCompiler
Dim oVBCompilerResults As CompilerResults
Dim oVBCompilerError As CompilerError
oVBCodeCompiler = oVBCodeProvider.CreateCompiler
With mVBCompilerParameters
With .ReferencedAssemblies
For Each oDll As String In mImportedDlls
.Add(oDll)
Next
End With
End With
Dim oFiles() As String
ReDim oFiles(mFilesToCompile.Count - 1)
mFilesToCompile.CopyTo(oFiles, 0)
oVBCompilerResults = _
oVBCodeCompiler.CompileAssemblyFromFileBatch(mVBCompilerParameters, _
oFiles)
mVBCompilerResults = oVBCompilerResults
With oVBCompilerResults
Console.WriteLine("---------------------------------")
Console.WriteLine("COMPILER OUTPUT: ")
Console.WriteLine("---------------------------------")
For Each oOut As String In .Output
Console.WriteLine(oOut)
Next
End With
With oVBCompilerResults
Console.WriteLine("---------------------------------")
Console.WriteLine("COMPILER ERRORS: " & .Errors.Count)
Console.WriteLine("---------------------------------")
mVBCompilerErrors = .Errors
Dim ErrorLog As String
For Each oVBCompilerError In .Errors
ErrorLog += oVBCompilerError.ToString & vbNewLine
Console.WriteLine(oVBCompilerError.ToString)
Next
If .Errors.Count > 0 Then
Throw New Exception("The compiler has thrown the following errors:" & _
vbNewLine & ErrorLog)
End If
End With
Return oVBCompilerResults
End Function
End Class
Comments
With this code, you will create a VBNet compiler, but you can create a CSharpCodeProvider
instead of a VBCodeProvider
and compile C# code.
This class is a simple example of CodeDom power, but this namespace is huge and has powerful and very interesting capabilities for code generation.