From 01d17c4e5cc439cac241b08d0ea44084253970b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=9C=A8=E6=A3=AE=20=C2=B7=20=E4=BD=9C=E9=9C=96?= <16236903+NMSAzulX@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:46:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E7=A6=BB=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E5=87=8F=E5=B0=91=E4=BE=B5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HECompiler.cs | 44 ++ .../HESpinLock.cs | 33 ++ .../ProjectDynamicProxy.cs | 418 +++++++----------- .../VSCSharpMainFileWatcher.cs | 162 +++++++ .../VSCSharpProcessor.cs | 18 +- 5 files changed, 403 insertions(+), 272 deletions(-) create mode 100644 src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HECompiler.cs create mode 100644 src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HESpinLock.cs create mode 100644 src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpMainFileWatcher.cs diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HECompiler.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HECompiler.cs new file mode 100644 index 00000000..b84fad33 --- /dev/null +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HECompiler.cs @@ -0,0 +1,44 @@ +using Microsoft.CodeAnalysis; +using Natasha.CSharp.Compiler; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace Natasha.CSharp.Extension.HotExecutor +{ + internal static class HECompiler + { + private static readonly AssemblyCSharpBuilder _builderCache; + static HECompiler() + { + _builderCache = new(); + _builderCache.ConfigCompilerOption(opt => opt + .AppendCompilerFlag( + CompilerBinderFlags.IgnoreAccessibility | CompilerBinderFlags.IgnoreCorLibraryDuplicatedTypes | CompilerBinderFlags.GenericConstraintsClause | CompilerBinderFlags.SuppressObsoleteChecks)); + _builderCache + .UseRandomLoadContext() + .UseSmartMode() + .WithoutSemanticCheck() + .WithPreCompilationOptions() + .WithoutPreCompilationReferences() + .WithoutCombineUsingCode(); + } + + public static Assembly ReCompile(IEnumerable trees,bool isRelease) + { + _builderCache.WithRandomAssenblyName(); + _builderCache.SyntaxTrees.Clear(); + _builderCache.SyntaxTrees.AddRange(trees); + if (isRelease) + { + _builderCache.WithReleaseCompile(); + } + else + { + _builderCache.WithDebugCompile(); + } + return _builderCache.GetAssembly(); + } + } +} diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HESpinLock.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HESpinLock.cs new file mode 100644 index 00000000..4f8e29ac --- /dev/null +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/HESpinLock.cs @@ -0,0 +1,33 @@ +using System.Runtime.CompilerServices; +namespace Natasha.CSharp.Extension.HotExecutor +{ + internal class HESpinLock + { + + private int _lockCount = 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool GetLock() + { + return Interlocked.CompareExchange(ref _lockCount, 1, 0) == 0; + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetAndWaitLock() + { + while (Interlocked.CompareExchange(ref _lockCount, 1, 0) != 0) + { + Thread.Sleep(20); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReleaseLock() + { + + _lockCount = 0; + + } + } +} diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/ProjectDynamicProxy.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/ProjectDynamicProxy.cs index cd5f9b0f..e3bca4c6 100644 --- a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/ProjectDynamicProxy.cs +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/ProjectDynamicProxy.cs @@ -7,47 +7,46 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; +using static System.Reflection.Metadata.Ecma335.MethodBodyStreamEncoder; public static class ProjectDynamicProxy { - private static readonly FileSystemWatcher _delAndCreateAndRenameWatcher; - //private static readonly FileSystemWatcher _changeWatcher; - private static string? _mainFile; private static string? _className; - private static string? _proxyMethodName; + private static string? _proxyMethodName = "Main"; private static string? _argumentsMethodName; private static readonly ConcurrentDictionary _fileCache = new(); - private static readonly object _fileLock = new object(); + private static readonly object _runLock = new object(); private static readonly List _args = []; private static readonly VSCSharpProcessor _processor; private static readonly VSCSharpProjectFileWatcher _csprojWatcher; private static bool _isCompiling; - private static readonly AssemblyCSharpBuilder _builderCache; private static bool _isFaildBuild; internal static bool IsRelease; private readonly static CSharpParseOptions _debugOptions; private static Action? _endCallback; + private static readonly HESpinLock _buildLock; + private static readonly VSCSharpMainFileWatcher _mainWatcher; + //private static readonly MethodDeclarationSyntax _emptyMainTree; + //private static string _callMethod; static ProjectDynamicProxy() { - - _builderCache = new(); - _builderCache.ConfigCompilerOption(opt => opt - .AppendCompilerFlag( - Natasha.CSharp.Compiler.CompilerBinderFlags.IgnoreAccessibility | Natasha.CSharp.Compiler.CompilerBinderFlags.IgnoreCorLibraryDuplicatedTypes)); - _builderCache.UseRandomLoadContext(); - _builderCache.UseSmartMode(); - _builderCache.WithoutSemanticCheck(); - _builderCache.WithPreCompilationOptions(); - _builderCache.WithoutPreCompilationReferences(); - _builderCache.WithoutCombineUsingCode(); - _debugOptions = new CSharpParseOptions(LanguageVersion.Preview, preprocessorSymbols: ["DEBUG","RELEASE"]); + NatashaManagement.Preheating(true, true); + _debugOptions = new CSharpParseOptions(LanguageVersion.Preview, preprocessorSymbols: ["DEBUG", "RELEASE"]); +// var emptyTreeScript = @"internal class Program{ +// static void Main(){ } +//}"; +// _emptyMainTree = CSharpSyntaxTree.ParseText(emptyTreeScript).GetRoot().DescendantNodes().OfType().First(); + _buildLock = new(); + _mainWatcher = new(); + _processor = new(); _csprojWatcher = new(VSCSharpFolder.CSProjFilePath, async () => { - if (GetLock()) + if (_buildLock.GetLock()) { _isCompiling = true; #if DEBUG @@ -68,10 +67,11 @@ static ProjectDynamicProxy() #if DEBUG Console.WriteLine("抢占成功,将重新编译!"); #endif - ReleaseLock(); + _buildLock.ReleaseLock(); _csprojWatcher!.Notify(); return; } + #if DEBUG Console.WriteLine("构建成功,准备启动!"); #endif @@ -80,20 +80,19 @@ static ProjectDynamicProxy() #if DEBUG Console.WriteLine("启动成功,退出当前程序!"); #endif - try - { - Environment.Exit(0); - } - catch (Exception ex) - { - } - + //try + //{ + // Environment.Exit(0); + //} + //catch (Exception ex) + //{ + //} } } else { _isFaildBuild = true; - ReleaseLock(); + _buildLock.ReleaseLock(); #if DEBUG Console.WriteLine("构建失败!"); #endif @@ -106,152 +105,37 @@ static ProjectDynamicProxy() } }); - - _csprojWatcher.StartMonitor(); - _delAndCreateAndRenameWatcher = new FileSystemWatcher - { - Path = VSCSharpFolder.MainCsprojPath, - Filter = "*.cs", - EnableRaisingEvents = true, - IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite - }; - - //_changeWatcher = new FileSystemWatcher - //{ - // Path = VSCSharpFolder.MainCsprojPath, - // Filter = "*.cs", - // EnableRaisingEvents = true, - // IncludeSubdirectories = true, - // NotifyFilter = NotifyFilters.LastWrite - //}; - - AppDomain.CurrentDomain.ProcessExit += (sender, e) => - { - _delAndCreateAndRenameWatcher.Dispose(); - }; - - //_changeWatcher.Changed += async (sender, e) => - //{ - // Debug.WriteLine($"Changed: {e.FullPath}"); - // Console.WriteLine($"Changed: {e.ChangeType }{e.FullPath}"); - // if (e.ChangeType == WatcherChangeTypes.Changed) - // { - // if (CheckFileAvailiable(e.FullPath)) - // { - // ChangeFile(e.FullPath); - // await HotExecute(); - // } - // } - //}; - - _delAndCreateAndRenameWatcher.Created += async (sender, e) => - { - if (_isFaildBuild) - { - _csprojWatcher.Notify(); - return; - } -#if DEBUG - Console.WriteLine($"Created: {e.FullPath}"); -#endif - if (CheckFileAvailiable(e.FullPath)) - { - CreateFile(e.FullPath); - await HotExecute(); - } - - }; - - _delAndCreateAndRenameWatcher.Deleted += async (sender, e) => - { - if (_isFaildBuild) - { - _csprojWatcher.Notify(); - return; - } -#if DEBUG - Console.WriteLine($"Deleted: {e.FullPath}"); -#endif - if (CheckFileAvailiable(e.FullPath)) - { - DeleteFile(e.FullPath); - await HotExecute(); - } - }; - - _delAndCreateAndRenameWatcher.Renamed += async (sender, e) => + _mainWatcher.PreFunction = () => { if (_isFaildBuild) { _csprojWatcher.Notify(); - return; - } -#if DEBUG - Console.WriteLine($"Renamed: {e.OldFullPath} -> {e.FullPath}"); -#endif - - - if (e.OldFullPath.EndsWith(".cs")) - { - if (e.FullPath.EndsWith(".cs")) - { - if (CheckFileAvailiable(e.FullPath)) - { - CreateFile(e.FullPath); - } - if (CheckFileAvailiable(e.OldFullPath)) - { - DeleteFile(e.OldFullPath); - } - await HotExecute(); - } - else if (e.FullPath.StartsWith(e.OldFullPath) && e.FullPath.EndsWith(".TMP")) - { - if (CheckFileAvailiable(e.OldFullPath)) - { - ChangeFile(e.OldFullPath); - await HotExecute(); - } - } - + return true; } + return false; }; - _delAndCreateAndRenameWatcher.Error += Error; + _mainWatcher.AfterFunction = HotExecute; - static void CreateFile(string file) - { + _mainWatcher.ChangeFileAction = file => { var content = ReadFile(file); - if (file == _mainFile) - { - return; - } - var tree = NatashaCSharpSyntax.ParseTree(content, _debugOptions); + var tree = HandleTree(content); _fileCache[file] = tree; - } + }; - static void DeleteFile(string file) - { + _mainWatcher.DeleteFileAction = file => { _fileCache.TryRemove(file, out _); - } + }; - static void ChangeFile(string file) + _mainWatcher.CreateFileAction = file => { var content = ReadFile(file); - var tree = NatashaCSharpSyntax.ParseTree(content, _debugOptions); + var tree = HandleTree(content); _fileCache[file] = tree; - } - - static void RenameFile(string file) - { - DeleteFile(file); - CreateFile(file); - } - - + }; + _mainWatcher.StartMonitor(); } /// @@ -284,118 +168,124 @@ public static void BuildWithDebug() IsRelease = false; } - - private static int _lockCount = 0; - - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool GetLock() - { - return Interlocked.CompareExchange(ref _lockCount, 1, 0) == 0; - - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void GetAndWaitLock() + public static void AppendArgs(string arg) { - while (Interlocked.CompareExchange(ref _lockCount, 1, 0) != 0) - { - Thread.Sleep(20); - } + _args.Add(arg); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReleaseLock() + public static void AppendArgs(params string[] args) { - - _lockCount = 0; - + _args.AddRange(args); } - private static void CurrentDomain_ProcessExit(object sender, EventArgs e) + public static void ClearArgs() { - _delAndCreateAndRenameWatcher.Dispose(); + _args.Clear(); } - private static void Error(object sender, ErrorEventArgs e) - { - PrintException(e.GetException()); - } - private static void PrintException(Exception? ex) + private static bool _isFirstRun = true; + public static void Run(string? argumentsMethodName = "ProxyMainArguments") { - if (ex != null) + if (_isFirstRun) { - Console.WriteLine($"Message: {ex.Message}"); - Console.WriteLine("Stacktrace:"); - Console.WriteLine(ex.StackTrace); - Console.WriteLine(); - PrintException(ex.InnerException); - } - } + lock (_runLock) + { + if (_isFirstRun) + { + _isFirstRun = false; + _argumentsMethodName = argumentsMethodName; + var srcCodeFiles = Directory.GetFiles(VSCSharpFolder.MainCsprojPath, "*.cs", SearchOption.AllDirectories); - static bool CheckFileAvailiable(string file) - { - if (file.StartsWith(VSCSharpFolder.ObjPath) || file.StartsWith(VSCSharpFolder.BinPath)) + foreach (var file in srcCodeFiles) + { + if (_mainWatcher.CheckFileAvailiable(file)) + { + var content = ReadFile(file); + var tree = HandleTree(content); + var root = tree.GetRoot(); + _fileCache[file] = root.SyntaxTree; + + } + } + + //HotExecute(); + } + } + } +#if DEBUG + else { - return false; + Console.WriteLine("已经初始化过了!"); } - return true; - } +#endif - public static void AppendArgs(string arg) - { - _args.Add(arg); } - public static void AppendArgs(params string[] args) + private static SyntaxTree HandleTree(string content) { - _args.AddRange(args); - } - public static void ClearArgs() - { - _args.Clear(); - } - public static void Run(string proxyMethodName = "ProxyMain", string? argumentsMethodName= "ProxyMainArguments") - { - _proxyMethodName = proxyMethodName; - _argumentsMethodName = argumentsMethodName; - var srcCodeFiles = Directory.GetFiles(VSCSharpFolder.MainCsprojPath, "*.cs", SearchOption.AllDirectories); + var tree = NatashaCSharpSyntax.ParseTree(content, _debugOptions); + var root = tree.GetRoot(); - foreach (var file in srcCodeFiles) + var methodDeclarations = root.DescendantNodes().OfType(); + Dictionary replaceMethodCache = []; + foreach (var methodDeclaration in methodDeclarations) { - if (CheckFileAvailiable(file)) + var removeIndexs = new HashSet(); + // 获取方法体 + var methodBody = methodDeclaration.Body; + if (methodBody == null) + { + continue; + } + // 遍历方法体中的语句 + for (int i = 0; i < methodBody.Statements.Count; i++) { - var content = ReadFile(file); - //Console.WriteLine(file); - //Console.WriteLine(content); - //Console.WriteLine("------------"); - var tree = NatashaCSharpSyntax.ParseTree(content, null); - var mainMethod = tree.GetRoot().DescendantNodes() - .OfType() - .FirstOrDefault(m => m.Identifier.Text == "Main"); - - if (mainMethod != null) + // 获取当前语句 + var statement = methodBody.Statements[i]; + if (statement is ExpressionStatementSyntax) { - ClassDeclarationSyntax? parentClass = mainMethod.Parent as ClassDeclarationSyntax ?? throw new Exception("获取 Main 方法类名出现错误!"); - _className = parentClass.Identifier.Text; - - var proxyMethod = tree.GetRoot().DescendantNodes() - .OfType() - .FirstOrDefault(m => m.Identifier.Text == proxyMethodName); - - if (proxyMethod == null) + var trivias = statement.GetLeadingTrivia(); + foreach (var trivia in trivias) { - throw new Exception($"{_className} 中未找到 {proxyMethodName} 代理方法!"); + if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) && trivia.ToString().Trim().StartsWith("//Once")) + { + removeIndexs.Add(i); + break; + } } - _mainFile = file; } - _fileCache[file] = tree; + } + + // 如果找到,创建新的方法体列表并排除该语句 + if (removeIndexs.Count > 0) + { + var newMethodBody = new List(methodBody.Statements.Where((s, index) => !removeIndexs.Contains(index))); + replaceMethodCache[methodDeclaration] = methodDeclaration.WithBody(SyntaxFactory.Block(newMethodBody)); } } - HotExecute(); - } + foreach (var item in replaceMethodCache) + { +//#if DEBUG +// Console.WriteLine(); +// Console.WriteLine("方法:"); +// Console.WriteLine(item.Key.ToFullString()); +// Console.WriteLine("替换为:"); +// Console.WriteLine(item.Value.ToFullString()); +// Console.WriteLine(); +//#endif + root = root.ReplaceNode(item.Key, item.Value); + tree = root.SyntaxTree; + } + + var mainMethod = root.DescendantNodes() + .OfType() + .FirstOrDefault(m => m.Identifier.Text == "Main"); + if (mainMethod != null) + { + ClassDeclarationSyntax? parentClass = mainMethod.Parent as ClassDeclarationSyntax ?? throw new Exception("获取 Main 方法类名出现错误!"); + _className = parentClass.Identifier.Text; + } + return tree; + } //use FileStream read a text file private static string ReadFile(string file) { @@ -433,22 +323,12 @@ private static Task HotExecute() { try { - _builderCache.WithRandomAssenblyName(); - _builderCache.SyntaxTrees.Clear(); - _builderCache.SyntaxTrees.AddRange(_fileCache.Values); - if (IsRelease) - { - _builderCache.WithReleaseCompile(); - } - else - { - _builderCache.WithDebugCompile(); - } - var assembly = _builderCache.GetAssembly(); + Console.Clear(); + var assembly = HECompiler.ReCompile(_fileCache.Values,IsRelease); var types = assembly.GetTypes(); var typeInfo = assembly.GetTypeFromShortName(_className!); var methods = typeInfo.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); - + _endCallback?.Invoke(); if (methods.Any(item => item.Name == _argumentsMethodName)) { @@ -459,23 +339,33 @@ private static Task HotExecute() var proxyMethodInfo = typeInfo.GetMethod(_proxyMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); object? instance = null; - if (!proxyMethodInfo.IsStatic) - { - instance = Activator.CreateInstance(typeInfo); - } - if (proxyMethodInfo.GetParameters().Length == 1) + try { - proxyMethodInfo.Invoke(instance, [_args.ToArray()]); + + if (!proxyMethodInfo.IsStatic) + { + instance = Activator.CreateInstance(typeInfo); + } + + if (proxyMethodInfo.GetParameters().Length > 0) + { + proxyMethodInfo.Invoke(instance, [_args.ToArray()]); + } + else + { + proxyMethodInfo.Invoke(instance, []); + } } - else + catch (Exception ex) { - proxyMethodInfo.Invoke(instance, []); + Console.WriteLine(ex.Message); } } catch (Exception ex) { Console.WriteLine($"Error during hot execution: {ex}"); + } return Task.CompletedTask; } diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpMainFileWatcher.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpMainFileWatcher.cs new file mode 100644 index 00000000..3403b6aa --- /dev/null +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpMainFileWatcher.cs @@ -0,0 +1,162 @@ +using Natasha.CSharp.Compiler.Component; +using System; +using System.Collections.Generic; +using System.Net.Http.Headers; +using System.Text; + +namespace Natasha.CSharp.Extension.HotExecutor +{ + internal class VSCSharpMainFileWatcher + { + private FileSystemWatcher _mainWatcher; + public Func PreFunction; + public Func AfterFunction; + public Action DeleteFileAction; + public Action CreateFileAction; + public Action ChangeFileAction; + private readonly HESpinLock _compileLock; + public VSCSharpMainFileWatcher() + { + _mainWatcher = new(); + _compileLock = new(); + PreFunction = () => false; + AfterFunction = () => Task.CompletedTask; + DeleteFileAction = (str) => { }; + CreateFileAction = (str) => { }; + ChangeFileAction = (str) => { }; + } + + public void StartMonitor() + { + _mainWatcher = new FileSystemWatcher + { + Path = VSCSharpFolder.MainCsprojPath, + Filter = "*.cs", + EnableRaisingEvents = true, + IncludeSubdirectories = true, + NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite + }; + + AppDomain.CurrentDomain.ProcessExit += (sender, e) => + { + _mainWatcher.Dispose(); + }; + + _mainWatcher.Created += async (sender, e) => + { + if (PreFunction()) + { + return; + } +#if DEBUG + Console.WriteLine($"Created: {e.FullPath}"); +#endif + + if (CheckFileAvailiable(e.FullPath)) + { + _compileLock.GetAndWaitLock(); + CreateFileAction(e.FullPath); + _compileLock.ReleaseLock(); + await ExecuteAfterFunction(); + } + + }; + + _mainWatcher.Deleted += async (sender, e) => + { + if (PreFunction()) + { + return; + } +#if DEBUG + Console.WriteLine($"Deleted: {e.FullPath}"); +#endif + if (CheckFileAvailiable(e.FullPath)) + { + _compileLock.GetAndWaitLock(); + DeleteFileAction(e.FullPath); + _compileLock.ReleaseLock(); + await ExecuteAfterFunction(); + } + + }; + + _mainWatcher.Renamed += async (sender, e) => + { + if (PreFunction()) + { + return; + } +#if DEBUG + Console.WriteLine($"Renamed: {e.OldFullPath} -> {e.FullPath}"); +#endif + if (e.OldFullPath.EndsWith(".cs")) + { + if (e.FullPath.EndsWith(".cs")) + { + _compileLock.GetAndWaitLock(); + if (CheckFileAvailiable(e.FullPath)) + { + CreateFileAction(e.FullPath); + } + if (CheckFileAvailiable(e.OldFullPath)) + { + DeleteFileAction(e.OldFullPath); + } + _compileLock.ReleaseLock(); + await ExecuteAfterFunction(); + } + else if (e.FullPath.StartsWith(e.OldFullPath) && e.FullPath.EndsWith(".TMP")) + { + + if (CheckFileAvailiable(e.OldFullPath)) + { + _compileLock.GetAndWaitLock(); + ChangeFileAction(e.OldFullPath); + _compileLock.ReleaseLock(); + await ExecuteAfterFunction(); + } + } + + } + }; + _mainWatcher.Error += Error; + } + private async Task ExecuteAfterFunction() + { + if (_compileLock.GetLock()) + { + await AfterFunction(); + _compileLock.ReleaseLock(); + } +#if DEBUG + else{ + Console.WriteLine($"争抢编译,做出让步!"); + } +#endif + } + public bool CheckFileAvailiable(string file) + { + if (file.StartsWith(VSCSharpFolder.ObjPath) || file.StartsWith(VSCSharpFolder.BinPath)) + { + return false; + } + return true; + } + private static void Error(object sender, ErrorEventArgs e) + { + PrintException(e.GetException()); + } + private static void PrintException(Exception? ex) + { + if (ex != null) + { + Console.WriteLine($"Message: {ex.Message}"); + Console.WriteLine("Stacktrace:"); + Console.WriteLine(ex.StackTrace); + Console.WriteLine(); + PrintException(ex.InnerException); + } + } + } +} diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpProcessor.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpProcessor.cs index e1f8cb62..237f0bc7 100644 --- a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpProcessor.cs +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.HotExecutor/VSCSharpProcessor.cs @@ -13,6 +13,7 @@ public class VSCSharpProcessor public VSCSharpProcessor() { + _process = Process.GetCurrentProcess(); _outpuNewAppFolder = string.Empty; _outputNewExeFile = string.Empty; _builder = new ProcessStartInfo() @@ -85,14 +86,8 @@ public ValueTask Run() { try { - if (_process != null) - { - _process.Kill(); - _process.Dispose(); - - } - _process = new Process() + var process = new Process() { StartInfo = new() { @@ -105,7 +100,7 @@ public ValueTask Run() #if DEBUG Console.WriteLine($"执行: {Path.Combine(_outpuNewAppFolder, VSCSharpFolder.ExecuteName)}"); #endif - _process.Start(); + process.Start(); // 等待一小段时间,让进程有机会启动 System.Threading.Thread.Sleep(1000); Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(_outputNewExeFile)); @@ -117,6 +112,13 @@ public ValueTask Run() { if (item.HasExited == false) { + //释放前一个进程 + if (_process != null) + { + _process.Kill(); + _process.Dispose(); + _process = process; + } return new ValueTask(true); } }