我正在编写一个动态编译和执行 C# 代码的项目。问题是有时我希望代码调用另一个 DLL(为了这个示例,我将其称为“ANOTHER.DLL”)。它在 .Net 4.5 中运行良好,但在 .Net Core 中失败,我不明白为什么。感谢您的帮助!
代码编译成功,但在执行该方法时出错。错误是:
FileNotFoundException: Could not load file or assembly 'ANOTHER, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
ANOTHER.dll 位于相同的 /bin/debug
文件夹中,绝对可以访问(代码编译!)
我注意到我可以通过在项目中添加对 ANOTHER.DLL 的引用来解决这个问题,但这违背了动态编译的目的。
我在 .Net Core 2.0 - 3.1 中试过这个
ANOTHER.DLL 是 .Net Standard 2.0(但与 .Net Standard 2.1 或 .Net Framework 的结果相同)。
还尝试了各种版本的 Microsoft.CodeAnalysis
包,都给我同样的错误。
var eval = new Evaluator();
string code = @"
using System;
namespace RoslynCompileSample
{
public class Test
{
public string Hello{
get {
//return ""Hello"";
var c = new ANOTHER.Class1();
return c.HelloWorld();
}
}
}
}";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
List < MetadataReference > references = new List < MetadataReference > ();
references.Add(MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location));
string ReferenceList = "";
ReferenceList += "netstandard.dll\n";
ReferenceList += "System.Runtime.dll\n";
ReferenceList += "ANOTHER.dll\n";
string[] assemblies = ReferenceList.Split('\n');
foreach(string a in assemblies) {
if (File.Exists(Path.Combine(assemblyPath, a.Trim()))) {
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, a.Trim())));
}
else if (File.Exists(a.Trim())) {
string currDirectory = Directory.GetCurrentDirectory();
references.Add(MetadataReference.CreateFromFile(Path.Combine(currDirectory, a.Trim())));
}
else {
string exepath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
if (File.Exists(Path.Combine(exepath, a.Trim()))) {
references.Add(MetadataReference.CreateFromFile(Path.Combine(exepath, a.Trim())));
}
}
}
CSharpCompilation compilation = CSharpCompilation.Create("assembly", syntaxTrees: new[] {
syntaxTree
},
references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release));
Assembly assembly;
using(var ms = new MemoryStream()) {
EmitResult result = compilation.Emit(ms);
ms.Seek(0, SeekOrigin.Begin);
assembly = Assembly.Load(ms.ToArray());
}
var type = assembly.GetType("RoslynCompileSample.Test");
var prop = type.GetProperties();
var all = prop.Where(x =>x.Name == "Hello");
var info = all.FirstOrDefault(x =>x.DeclaringType == type) ? ?all.First();
var method = info.GetGetMethod();
object obj;
obj = assembly.CreateInstance("RoslynCompileSample.Test");
object r = method.Invoke(obj, new object[] {}); // this is where the error occurs
最佳答案
解决方案基于我的要点
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
string code = @"
using System;
namespace RoslynCompileSample
{
public class Test
{
public string Hello{
get {
//return ""Hello"";
var c = new ANOTHER.Class1();
return c.HelloWorld();
}
}
}
}";
var tree = SyntaxFactory.ParseSyntaxTree(code);
string fileName = "mylib.dll";
var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
List<MetadataReference> references = new List<MetadataReference>();
references.Add(MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location));
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "netstandard.dll")));
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll")));
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Private.CoreLib.dll")));
var anotherDLLReference = MetadataReference.CreateFromFile(@"C:\Users\jjjjjjjjjjjj\source\repos\ConsoleApp2\ANOTHER\bin\Debug\netcoreapp3.1\ANOTHER.dll");
references.Add(anotherDLLReference);
var compilation = CSharpCompilation.Create(fileName)
.WithOptions(
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(references)
.AddSyntaxTrees(tree);
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);
EmitResult compilationResult = compilation.Emit(path);
if (compilationResult.Success)
{
// Load the assembly
Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
var type = assembly.GetType("RoslynCompileSample.Test");
var prop = type.GetProperties();
var all = prop.Where(x => x.Name == "Hello");
var info = all.FirstOrDefault(x => x.DeclaringType == type) ?? all.First();
var method = info.GetGetMethod();
object obj;
obj = assembly.CreateInstance("RoslynCompileSample.Test");
object r = method.Invoke(obj, new object[] { });
}
}
}
}
公平地说,我不知道它是如何工作的,因为我不熟悉在这个级别上使用程序集,但不知何故我设法摆脱了异常。
首先,我在调试器中检查了 AssemblyLoadContext.Default
。我注意到缺少对“ANOTHER.dll”的引用(尽管我们之前添加了它)
然后我添加了 AssemblyLoadContext.Default.LoadFromAssemblyPath(@"path to my ANOTHER.dll");
。当我再次检查时 - ANOTHER.dll 在那里。
最后,我们可以看到我们的 hello world 消息
所以我添加的代码基本上就是一行
// Load the assembly
Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
var a = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\Users\jjjjjjjjjjjj\source\repos\ConsoleApp2\ANOTHER\bin\Debug\netcoreapp3.1\ANOTHER.dll");
var type = assembly.GetType("RoslynCompileSample.Test");
这适用于针对 Standard 2.0 和 .NET Core 3.1 的 ANOTHER.dll
如果有人聪明地告诉它是如何工作的,那就太好了。
关于c# - 如何在 Roslyn 动态编译代码中引用另一个 DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64365731/