UnityEditor中执行merge后C#脚本意外终止问题排查
问题原因与解决方案
问题代码
[MenuItem("bat/merge")] public static void merge(){ Process p = GetNewProcess("git_merge.bat"); p.Exited+=(obj,e)=>{ if(p.ExitCode == -1) return; Debug.Log(p.ExitCode); // 以下代码无法执行,访问Editor API导致静默终止 Debug.Log(PlayerSettings.bundleVersion); if(Application.isPlaying)... }; p.Start(); }
原因分析
Unity的Editor相关API(比如PlayerSettings、Application.isPlaying)只能在Unity Editor的主线程中调用,而Process.Exited的回调是在.NET线程池的子线程中触发的。跨线程调用非线程安全的Editor API会导致静默执行终止,且不会抛出任何异常,这就是后续代码无法运行的原因。
解决方案
把需要访问Editor API的逻辑放到Unity主线程中执行,这里用EditorApplication.update实现主线程调度:
using UnityEditor; using System.Diagnostics; using System.Collections.Generic; public class BatMergeHandler { private static Queue<System.Action> _mainThreadActions = new Queue<System.Action>(); [MenuItem("bat/merge")] public static void Merge() { // 注册主线程更新回调,处理队列中的动作 EditorApplication.update += ProcessMainThreadQueue; Process p = GetNewProcess("git_merge.bat"); p.EnableRaisingEvents = true; // 必须开启,否则Exited事件不会触发 p.Exited += (obj, e) => { if (p.ExitCode == -1) return; Debug.Log(p.ExitCode); // 将需要在主线程执行的逻辑加入队列 _mainThreadActions.Enqueue(() => { Debug.Log(PlayerSettings.bundleVersion); if (Application.isPlaying) { // 此处编写你的业务逻辑 } }); }; p.Start(); } private static void ProcessMainThreadQueue() { // 执行队列中所有待处理的主线程逻辑 while (_mainThreadActions.Count > 0) { _mainThreadActions.Dequeue().Invoke(); } // 执行完毕后取消注册,避免重复触发 EditorApplication.update -= ProcessMainThreadQueue; } private static Process GetNewProcess(string batPath) { // 补充GetNewProcess的实现示例 var startInfo = new ProcessStartInfo(batPath) { UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true }; return new Process { StartInfo = startInfo }; } }
核心要点
- 用队列存储主线程待执行逻辑,通过
EditorApplication.update在主线程帧循环中处理。 - 必须设置
Process.EnableRaisingEvents = true,否则Exited事件不会被触发。 - 执行完队列逻辑后取消
EditorApplication.update的注册,避免不必要的性能开销。
内容的提问来源于stack exchange,提问作者rocmon
相关产品推荐
相关产品推荐

