You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 21:25:17