diff --git a/.idea/.idea.FantasyNetTest/.idea/vcs.xml b/.idea/.idea.FantasyNetTest/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.FantasyNetTest/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FantasyNetTest/Form1.cs b/FantasyNetTest/Form1.cs index 57d0849..a3a33bb 100644 --- a/FantasyNetTest/Form1.cs +++ b/FantasyNetTest/Form1.cs @@ -328,7 +328,7 @@ public partial class Form1 : Form private void LoadProtocol() { Log.Info("开始加载协议"); - _scriptLoader.LoadAndExecuteScriptsAsync(_config.ProtocolScriptPath); + _scriptLoader.LoadAndExecuteScripts(_config.ProtocolScriptPath); Log.Succeed("加载协议完成"); CoderLoader.Load(); SetProtocolComboBox(); diff --git a/FantasyNetTest/Loader/ScriptLoader.cs b/FantasyNetTest/Loader/ScriptLoader.cs index 9b77cc8..0e2f121 100644 --- a/FantasyNetTest/Loader/ScriptLoader.cs +++ b/FantasyNetTest/Loader/ScriptLoader.cs @@ -1,22 +1,26 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; -using System.Threading.Tasks; -using FantasyNetTest; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Scripting; -using Microsoft.CodeAnalysis.Scripting; -using NBC; public class ScriptLoader { - public void LoadAndExecuteScriptsAsync(string folderPath) + private AssemblyLoadContext _lastContext; + + public void LoadAndExecuteScripts(string folderPath) { - // 1. 读取所有 .cs 文件 + // 如果有旧的上下文,卸载它 + if (_lastContext != null) + { + _lastContext.Unload(); + _lastContext = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + var csFiles = Directory.GetFiles(folderPath, "*.cs", SearchOption.AllDirectories); if (!csFiles.Any()) @@ -25,20 +29,20 @@ public class ScriptLoader return; } - // 2. 创建语法树 var syntaxTrees = csFiles.Select(file => CSharpSyntaxTree.ParseText(File.ReadAllText(file)) ); - // 3. 引用程序集 var references = AppDomain.CurrentDomain.GetAssemblies() .Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location)) .Select(a => MetadataReference.CreateFromFile(a.Location)) .Cast(); - // 4. 编译成内存程序集 + // 每次给程序集一个唯一名字 + string asmName = $"DynamicScripts_{Guid.NewGuid():N}"; + var compilation = CSharpCompilation.Create( - assemblyName: "DynamicScripts", + assemblyName: asmName, syntaxTrees: syntaxTrees, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) @@ -54,14 +58,15 @@ public class ScriptLoader return; } - // 5. 加载程序集 ms.Seek(0, SeekOrigin.Begin); - - var assembly = AssemblyLoadContext.Default.LoadFromStream(ms); - // 6. 调用示例 - var type = assembly.GetType("MyNamespace.MyClass"); // 你的类名 - var method = type?.GetMethod("Run"); // 你的方法名 - method?.Invoke(null, null); // 假设是静态方法无参数 + // 用可卸载的 AssemblyLoadContext 加载 + var alc = new AssemblyLoadContext(asmName, isCollectible: true); + var assembly = alc.LoadFromStream(ms); + _lastContext = alc; + + var type = assembly.GetType("MyNamespace.MyClass"); + var method = type?.GetMethod("Run"); + method?.Invoke(null, null); } -} \ No newline at end of file +}