Timothy Klenke Timothy Klenke - 5 months ago 22
Vb.net Question

How to feed Imported Namespaces into CompileAssemblyFromSource

I'm trying to load a VB source file into memory. However, the VB file assumes that Project it is associated to has some global "Imported Namespaces" defined at the project level. This VB feature allows individual files to omit the Imports statement (Using in C#) on every single file.

Dim sourceCode As String = ""
'sourceCode &= "Imports System.Data" & vbNewLine
sourceCode &= "Class Foo" & vbNewLine
sourceCode &= "Sub Print()" & vbNewLine
sourceCode &= "Dim dtbl As DataTable" & vbNewLine
sourceCode &= "System.Console.WriteLine(""Hello, world!"")" & vbNewLine
sourceCode &= "End Sub" & vbNewLine
sourceCode &= "End Class" & vbNewLine

Dim compiler As New Microsoft.VisualBasic.VBCodeProvider

Dim params As New Compiler.CompilerParameters
params.ReferencedAssemblies.Add("System.dll")
params.ReferencedAssemblies.Add("System.Data.dll")
params.ReferencedAssemblies.Add("System.Xml.dll")
params.GenerateInMemory = True
params.GenerateExecutable = False

Dim results As Compiler.CompilerResults = compiler.CompileAssemblyFromSource(params, sourceCode)

If results.Errors.Count > 0 Then
For Each compileError In results.Errors
Console.WriteLine(compileError.ToString)
Next
Return
End If

Dim assembly = results.CompiledAssembly


Line 2 is commented out. If I uncomment this and add the Imports statement the code works fine. It also works fine if I change "Dim dtbl As DataTable" to "Dim dtbl As System.Data.DataTable".

Instead of uncommenting that line of code, is there a way to feed this Imports statement into the compiler or params as if it was a global project level Imported Namespace?

I could just add this Imports statement to the top of each file I read in. But if it is already there then I get an error that the Imports statement is duplicate. I could do some Regex checking to see if the Imports statement is already there, but I'd like to leverage the System.CodeDom framework as much as possible.

Answer

OK, no answers :( I guess the framework doesn't do what I'd like to do. Here is my hacky solution using Regex to inject the Imports statement.

sourceCode = AddImportsIfNeeded(sourceCode, "System.Data")


Private Function AddImportsIfNeeded(ByVal sourceCode As String, ByVal namespaceToImport As String) As String

    If Not Regex.IsMatch(sourceCode, "^\s*Imports\s+" & Regex.Escape(namespaceToImport) & "\s*$", RegexOptions.Multiline) Then
        Return "Imports " & namespaceToImport & vbNewLine & sourceCode
    End If
    Return sourceCode

End Function

Note that this won't work if the file contains Option statements (like Option Strict On). The Imports statements must go below the Option statements.