从.txt文件加载VB.net代码,并使用System.CodeDom.Compiler在飞行中执行它

时间:2014-01-27 11:40:07

标签: vb.net codedom

我已经在这篇文章中找到了对这个问题的回答:https://stackoverflow.com/a/14711110/1764912

但我的下一个查询是,当我尝试在此动态代码中声明DataTable或MsgBox时,它给出了一个错误“未定义类型'DataTable'”和“未定义类型'MsgBox'”是。如果我使用动态代码中的第一行添加导入:

Imports System.Data

Imports System.Data.DataTable

或者如果我在GenerateScript()函数中使用以下任何代码(请参考https://stackoverflow.com/a/14711110/1764912获取GenerateScript()函数)

Dim importDataNameSpace As String = GetType(DataTable).Namespace
Dim codeArray() As String = New String() {"Imports " & importDataNameSpace & Environment.NewLine & code}

或者如果我使用

Dim codeArray() As String = New String() {"Imports System.Data" & Environment.NewLine & code}

Dim codeArray() As String = New String() {"Imports System.Data.DataTable" & Environment.NewLine & code}

在上述所有情况下,它都会给我一个错误“System.Data不包含任何公共成员或找不到”。

1 个答案:

答案 0 :(得分:6)

除非您首先引用库,否则导入名称空间不会对您有任何帮助。如果未引用库,则您导入的命名空间实际上将为空。

正如其他人在上面的评论中提到的那样,仅仅因为您在项目中引用了System.Data.dll库,这并不意味着它也会被您动态编译的程序集引用。每个程序集都需要直接引用它需要的所有程序集。动态编译的程序集也不例外。

通过CompilerParameters.ReferencedAssemblies.Add方法将引用添加到动态程序集中。您可以在我对您链接的问题的回答中看到一个示例。在该示例中,我将动态程序集引用返回到主程序集,以便它可以使用IScript接口。但是,您可以根据需要添加任意数量的引用。要添加对System.Data.dll的引用,您可以这样做:

Public 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.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

由于System.Data.dll程序集位于GAC中,因此您无需指定完整路径。另请注意,为了使用DataTable,您还需要添加对System.Xml.dll的引用。一旦运行代码,就会发现它。

因此,如果您定义了上述方法,并且您定义了以下接口:

Public Interface IScript
    Function DoWork() As String
End Interface

然后,你可以这样称呼它:

Dim builder As New StringBuilder()
builder.AppendLine("Public Class Script")
builder.AppendLine("    Implements IScript")
builder.AppendLine("    Public Function DoWork() As String Implements IScript.DoWork")
builder.AppendLine("        Dim table As New System.Data.DataTable()")
builder.AppendLine("        table.TableName = ""Hello World""")
builder.AppendLine("        Return table.TableName")
builder.AppendLine("    End Function")
builder.AppendLine("End Class")
Dim script As IScript = GenerateScript(builder.ToString())
Console.WriteLine(script.DoWork())  ' Outputs "Hello World"