You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中用Roslyn编译后如何设置外部对象到程序集字段

解决Roslyn编译后为动态程序集字段赋值的问题

你混淆了Roslyn的编译阶段API和运行时反射API:Roslyn的符号(Symbol)、语法树(SyntaxTree)是编译时的代码分析工具,仅用于检查代码结构;而字段赋值需要在编译完成后,将生成的程序集加载到内存,再用标准的System.Reflection API操作——这和CodeDom的实现逻辑完全一致,只是Roslyn获取编译后程序集的步骤不同。

完整的Roslyn实现代码

以下是补充了字段赋值、方法执行逻辑的完整代码:

'Roslyn example
'Add reference paths
Dim refPaths = {GetType(System.Object).GetTypeInfo().Assembly.Location,
                GetType(Console).GetTypeInfo().Assembly.Location,
                Path.Combine(Path.GetDirectoryName(GetType(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"),
                Path.Combine(Path.GetDirectoryName(GetType(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Data.dll"),
                Path.Combine(Path.GetDirectoryName(GetType(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.XML.dll"),
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly.Location) & "\CustomDLL.dll"}
Dim references As Microsoft.CodeAnalysis.MetadataReference() = refPaths.[Select](Function(r) MetadataReference.CreateFromFile(r)).ToArray()

'Script example. Formatted for readability.
Dim sb As StringBuilder = New StringBuilder
sb.Append(
"Option Strict Off
 Option Explicit On
 Imports System
 Imports System.XML
 Imports System.Data
 Imports Microsoft.VisualBasic
 Imports Microsoft.VisualBasic.Compatibility
 Imports CustomDLL

 Module Script 
      Public app as Object

      Sub ProcessName()
           Call app.Execute(app.statements.executeStatement(1))
           Call app.Execute(app.statements.executeStatement(2))
           ...
      End Sub
 End Module")
 Dim syntax As Microsoft.CodeAnalysis.SyntaxTree = VisualBasicSyntaxTree.ParseText(sb.ToString())

'Compile options
Dim assemblyName As String = Path.GetRandomFileName()
Dim compileOpts As New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
                                                             embedVbCoreRuntime:=True)

'Compile
Dim objVBCompilation As Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation = VisualBasicCompilation.Create(assemblyName,
                                                syntaxTrees:={syntax},
                                                references:=references,
                                                options:=compileOpts)

' --- 编译并加载程序集 ---
Using ms As New MemoryStream()
    Dim emitResult = objVBCompilation.Emit(ms)
    If Not emitResult.Success Then
        ' 处理编译错误
        For Each diagnostic In emitResult.Diagnostics.Where(Function(d) d.Severity = DiagnosticSeverity.Error)
            Console.WriteLine($"编译错误: {diagnostic.GetMessage()}")
        Next
        Return
    End If
    
    ' 重置内存流位置,加载程序集
    ms.Seek(0, SeekOrigin.Begin)
    Dim compiledAssembly As Assembly = Assembly.Load(ms.ToArray())
    
    ' --- 为app字段赋值(和CodeDom逻辑完全一致) ---
    Dim scriptType As Type = compiledAssembly.GetType("Script")
    Dim appField As FieldInfo = scriptType.GetField("app")
    ' objApp为外部全局对象,类型定义来自CustomDLL
    appField.SetValue(Nothing, CType(objApp, Object))
    
    ' --- 执行ProcessName方法 ---
    Dim processMethod As MethodInfo = scriptType.GetMethod("ProcessName")
    Dim returnObj As Object = processMethod.Invoke(Nothing, Nothing)
End Using

关键步骤说明

  1. 编译生成字节流:调用objVBCompilation.Emit(ms)将编译结果写入内存流,替代CodeDom的CompileAssemblyFromSource方法。
  2. 加载程序集:通过Assembly.Load(ms.ToArray())将内存中的程序集字节加载到当前AppDomain,得到可操作的Assembly实例。
  3. 反射操作成员:后续的GetType、GetField、SetValue、Invoke调用和CodeDom代码完全相同——无论用哪种工具编译,最终生成的都是标准.NET程序集,反射API是通用的。

误区澄清

  • Roslyn的ISymbol、SyntaxTree仅用于编译时的代码分析,无法直接修改运行时的字段值。
  • 只要成功生成合法的.NET程序集,就可以用System.Reflection操作所有类型成员,和编译工具无关。

内容的提问来源于stack exchange,提问作者andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 10:26:06