从 .txt 文件加载 VB.net 代码并使用 System.CodeDom.Compiler 即时执行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21379926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 16:35:30  来源:igfitidea点击:

Load VB.net code from .txt file and execute it on fly using System.CodeDom.Compiler

vb.netcodedom

提问by SMultani

I have found answer to this question already in this post : https://stackoverflow.com/a/14711110/1764912

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

But my next query is, When I try to declare either a DataTable or MsgBox inside this dynamic code, it give me an error that "Type 'DataTable' is not defined" and "Type 'MsgBox' is not defined" is. If I add imports using either first line in dynamic code as :

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

Imports System.Data

or

或者

Imports System.Data.DataTable

or if I use any of the following code in GenerateScript() function (Please refer https://stackoverflow.com/a/14711110/1764912for GenerateScript() function)

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

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

or if I use

或者如果我使用

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

or

或者

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

In all above cases, it give me an error "System.Data does not contain any public members or couldn't found".

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

回答by Steven Doggart

Importing namespaces does nothing for you unless you first also referencethe library. If the library isn't referenced, then the namespace that you're importing will effectively be empty.

导入命名空间对您没有任何作用,除非您首先还引用了该库。如果未引用该库,则您正在导入的命名空间实际上是空的。

As others have mentioned in the comments above, just because you have the System.Data.dlllibrary referenced in your project, that doesn't mean that it is also referenced by the assembly that you are dynamically compiling. Each assembly needs to directly reference all of the assemblies that it needs. Dynamically compiled assemblies are no exception.

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

References are added to the dynamic assembly via the CompilerParameters.ReferencedAssemblies.Addmethod. You can see an example of that in my answer to the question that you linked to. In that example, I had the dynamic assembly reference back to the main assembly so that it could use the IScriptinterface. You can, however, add as many references as you like. To also add a reference to System.Data.dll, you could do it like this:

通过该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

Since the System.Data.dllassembly is in the GAC, you don't need to specify a full path. Notice also, that in order to use DataTable, you'll also need to add a reference to System.Xml.dll. You'd find that out as soon as you ran the code.

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

So, if you had the above method defined, and you had the following interface defined:

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

Public Interface IScript
    Function DoWork() As String
End Interface

Then, you'd be able to call it like this:

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

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"