在上一篇Roslyn的文章中 - Roslyn动态编译DLL和缺少Private.CoreLib的问题 我们成功的动态编译了DLL文件,那么我们今天来继续研究在Roslyn中使用。
本文研究的是如何从开始简单的调用DLL,到最后在不同的ALC中加载运行。
加载DLL,为了后面的卸载功能。这里统一使用AssemblyLoadContext,后面统一叫ALC。更简单的可以直接使用Assembly.Load,不是本文重点,请自行研究。
我们先复习下怎么制作DLL,见 Roslyn动态编译DLL和缺少Private.CoreLib的问题 ,我们编译这个code0.cs文件,距离步骤这里不写了。
using System;
namespace RoslynCompileSample
{
public class Funs
{
public static string GetName()
{
return ""Get Funs.Name ()"";
}
}
}
放到c:\Temp\code0.dll。
我们把dll加载到一个名为mydll的ALC中
string path = @"c:\Temp\code0.dll";
string contextname = "mydll";
AssemblyLoadContext alc_dll = new AssemblyLoadContext(contextname, true);
Assembly ass = alc_dll.LoadFromAssemblyPath(path);
全部脚本:
public void LoadDll()
{
//读取程序集MyLib.dll
string mydllPath = @"c:\Temp\code0.dll";
string contextname = "code0";
AssemblyLoadContext alc_dll = new AssemblyLoadContext(contextname, true);
Assembly ass = alc_dll.LoadFromAssemblyPath(mydllPath);
//创建动态脚本调用
string sourceCode = File.ReadAllText(@"c:\Temp\my.cs");
SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(sourceCode));
List < MetadataReference > list = new List<MetadataReference>();
string dllpath = @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.9\ref\net7.0\";
list.Add(MetadataReference.CreateFromFile(dllpath + "mscorlib.dll"));
list.Add(MetadataReference.CreateFromFile(dllpath + "System.Runtime.dll"));
list.Add(MetadataReference.CreateFromFile(dllpath + "System.Console.dll"));
//添加我的mylib.dll的引用
list.Add(MetadataReference.CreateFromFile(mydllPath));
// 创建编译对象
CSharpCompilation compilation = CSharpCompilation.Create(
"my",
new[] { syntaxTree },
list,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
)
;
using (var ms = new MemoryStream())
{
// 将编译好的IL代码放入内存流
EmitResult result = compilation.Emit(ms);
// 编译失败,提示
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
}
else
{
ms.Seek(0, SeekOrigin.Begin);
// 编译成功,从内存中加载编译好的程序集
Assembly assembly = alc_dll.LoadFromStream(ms);
if (assembly != null)
{
Type type = null;
object obj = null;
type = assembly.GetType("RoslynCompileSample.Writer");
obj = Activator.CreateInstance(type);
// 通过反射方式调用类中的方法。(Hello World 便是我们传入方法的参数)
Console.Write("InvokeMember ...\n");
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
}
}
}
}
my.cs的内容为
using System;
namespace RoslynCompileSample
{
public class Writer
{
public void Write()
{
Console.WriteLine(""---"");
Console.WriteLine(MyLib.GetGreeting());
}
}
}
运行后直接得到结果。
这里就简单的运行了,这里注意几个点,我们的dll和mycs在同一个ALC中,如果要卸载会导致需要两个都要卸载。下一步我们把他们分别放在不同的ALC中。
我们把最后一段代码改为
AssemblyLoadContext mycs = new AssemblyLoadContext("mycs", true);
Assembly assembly = mycs.LoadFromStream(ms);
if (assembly != null)
{
Type type = null;
object obj = null;
type = assembly.GetType("RoslynCompileSample.Writer");
obj = Activator.CreateInstance(type);
// 通过反射方式调用类中的方法。(Hello World 便是我们传入方法的参数)
Console.Write("InvokeMember ...\n");
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
}
这里我们创建了一个新的名为mycs的ALC。我们运行一下看看
这里直接抛出了错误。无法找到code0,因为我们的两个执行文件在不同的ALC,这里他只会先找同一个ALC,如果没有会在ALC.Default中查找。那么怎么办呢?
如果把这两行代码换成了Default就可以运行了。
//AssemblyLoadContext alc_dll = new AssemblyLoadContext(contextname, true);
//Assembly ass = alc_dll.LoadFromAssemblyPath(mydllPath);
Assembly ass = AssemblyLoadContext.Default.LoadFromAssemblyPath(mydllPath);
但是这个Default是无法卸载的。
我们可以利用ALC的Resolving来处理。我们只需要增加下面的代码,让他返回正确的Assembly就可以了。
Resolving : 当尝试加载到此程序集加载上下文时程序集解析失败时发生。
AssemblyLoadContext mycs = new AssemblyLoadContext("mycs", true);
mycs.Resolving += (loadContext, assemblyName) =>
{
Console.WriteLine("--Resolving---" + loadContext.Name + "," + assemblyName);
return ass;
};
运行后,获取到了。
这样就可以实现不同的ALC中的上下文问题。
因为学习中,可能存在错误,还请留言。
https://zhuanlan.zhihu.com/p/636044493
https://learn.microsoft.com/zh-cn/dotnet/standard/assembly/unloadability