Roslyn - 使用 CSharpCompilation 编译程序集以在 CSharpCompilation 编译的另一个程序中使用
Posted
技术标签:
【中文标题】Roslyn - 使用 CSharpCompilation 编译程序集以在 CSharpCompilation 编译的另一个程序中使用【英文标题】:Roslyn - Use CSharpCompilation to compile assembly to be used in another program compiled by CSharpCompilation 【发布时间】:2020-10-12 21:02:12 【问题描述】:我正在尝试使用 CSharpCompilation
编译一个程序集,其中包含一个简单的类,然后我可以在另一个也通过 CSharpCompilation
编译的程序中引用它。我有这个代码:
命名空间编译测试 课堂节目 静态无效主要(字符串 [] 参数) HashSet 引用的Assemblies = new HashSet() typeof(object).Assembly, Assembly.Load(new AssemblyName("Microsoft.CSharp")), Assembly.Load(new AssemblyName("netstandard")), Assembly.Load(new AssemblyName("System.Runtime")), Assembly.Load(new AssemblyName("System.Linq")), Assembly.Load(new AssemblyName("System.Linq.Expressions")) ; 字符串问候语 = @" 命名空间 TestLibraryAssembly 公共静态类问候语 公共静态字符串 GetGreeting(字符串名称) 返回“”你好,“”+名称+“”!“”; "; CSharpCompilation 编译1 = CSharpCompilation.Create( "TestLibraryAssembly", 新的 [] CSharpSyntaxTree.ParseText(greetingClass) , referencedAssemblies.Select(assembly => MetadataReference.CreateFromFile(assembly.Location)).ToList(), 新 CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); MemoryStream memoryStream1 = new MemoryStream(); EmitResult emitResult1 = 编译1.Emit(memoryStream1); memoryStream1.Position = 0; MetadataReference testLibraryReference = MetadataReference.CreateFromStream(memoryStream1); 字符串程序代码 = @" 使用 TestLibraryAssembly; 命名空间测试程序 公开课程序 公共无效主要() 字符串问候 = Greeting.GetGreeting(""Name""); "; CSharpCompilation 编译2 = CSharpCompilation.Create( "测试程序", 新的 [] CSharpSyntaxTree.ParseText(programCode) , 引用的程序集 .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) .Concat(new ListtestLibraryReference ).ToList(), 新 CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); MemoryStream memoryStream2 = new MemoryStream(); EmitResult emitResult2 = 编译2.Emit(memoryStream2); memoryStream2.Position = 0; 汇编程序Assembly = Assembly.Load(memoryStream2.ToArray()); 类型 programType = programAssembly.GetType("TestProgram.Program"); MethodInfo 方法 = programType.GetMethod("Main"); 对象实例 = Activator.CreateInstance(programType); 方法。调用(实例,空);
但是,当我运行它时,我得到了这个错误:
未处理的异常。 System.Reflection.TargetInvocationException:调用的目标已引发异常。
---> System.IO.FileNotFoundException:无法加载文件或程序集“TestLibraryAssembly,Version=0.0.0.0,Culture=neutral,PublicKeyToken=null”。系统找不到指定的文件。
文件名:'TestLibraryAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
我该如何解决这个错误?
【问题讨论】:
【参考方案1】:您的示例中的问题是激活器 (Activator.CreateInstance(programType);
) 如何尝试解决依赖关系。它会在磁盘上查找文件。
解决此问题的一种方法是将文件保存在磁盘上,然后使用Activator.CreateInstanceFrom
创建实例。
您可以在这里找到一个正在执行此操作的 sn-p:
using System;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace Playground
public static class Program
private const string firstClass =
@"
namespace A
public class Foo
public int Bar() => 21;
";
private const string secondClass =
@"using A;
namespace B
public class Test
public int GetValue() => new Foo().Bar();
";
public static void Main()
var firstAssemblyFileName = Path.Combine(Path.GetTempPath(), "A.dll");
var secondAssemblyFileName = Path.Combine(Path.GetTempPath(), "B.dll");
var compilation = CreateCompilation(CSharpSyntaxTree.ParseText(firstClass), "A");
var secondCompilation = CreateCompilation(CSharpSyntaxTree.ParseText(secondClass), "B")
.AddReferences(compilation.ToMetadataReference());
compilation.Emit(firstAssemblyFileName);
secondCompilation.Emit(secondAssemblyFileName);
dynamic testType = Activator.CreateInstanceFrom(secondAssemblyFileName, "B.Test").Unwrap();
var value = testType.GetValue();
private static CSharpCompilation CreateCompilation(SyntaxTree tree, string name) =>
CSharpCompilation
.Create(name, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(MetadataReference.CreateFromFile(typeof(string).Assembly.Location))
.AddSyntaxTrees(tree);
【讨论】:
【参考方案2】:由于您使用的是netstandard
,因此没有引用System.IO
。
将此行添加到referencedAssemblies
HashSet 声明部分:
Assembly.Load("System.IO.FileSystem")
已编辑:
或者更安全的使用:
typeof(File).Assembly
【讨论】:
以上是关于Roslyn - 使用 CSharpCompilation 编译程序集以在 CSharpCompilation 编译的另一个程序中使用的主要内容,如果未能解决你的问题,请参考以下文章