UnityでEditor拡張から高速にC#コードを書いたり消したりする時のお作法
TL;DR
- 書いてる最中からコンパイルされてEditor拡張が走ってるアセンブリが猛然と破棄されたりする
- EditorApplication.LockReloadAssemblies, EditorApplication.UnlockReloadAssembliesで囲め
- AssetDatabase.StartAssetEditing, AssetDatabase.StopAssetEditingで囲め
どういうことか
Unityを使ってるとそのだるさから自動生成によるコード生成を行ったり、パッケージ管理がだるすぎて思わずパッケージマネージャを自作してしまうことがあると思う。
そのような場合には高速にスクリプトからC#コードを生成したり削除したりするわけだが、Unityはせっかちなので生成してるそばからコンパイルを始めて、実行中のコードがアセンブリごと破棄されたり、不完全なコンパイルがされたり、AssetDatabaseが一時的にぶっ壊れたりする。死ね
そのような場合には適切なAPIを各位やっていく必要がある
対処
AssetDatabaseの更新をスクリプトのコード編集中だけロックしてあげればいい。ついでにアセンブリリロードもロックしておくと安心できる。ちなみに超ステートフルなAPIとして実装されてるので、きっちり対応させて呼ばないとUnityが実質固まったり、いくらまってもあたらしいアセンブリがロードされなくなったりする。死ね
我々には文明があるので、IDisposableを実装する形で実装して、usingで適切にやっていけばよい
実装
以下のようなコードを書いた上で、高速にC#コードを書いたり消したりするコードブロックをusingで囲んでいく
using System; public class LockReloadAssembliesScope : IDisposable { public bool IsDisposed { get; private set; } public LockReloadAssembliesScope() { EditorApplication.LockReloadAssemblies(); IsDisposed = false; } public void Dispose() { if (!IsDisposed) { EditorApplication.UnlockReloadAssemblies(); IsDisposed = true; } } } public class AssetEditingScope : IDisposable { public bool IsDisposed { get; private set; } public AssetEditingScope() { AssetDatabase.StartAssetEditing(); IsDisposed = false; } public void Dispose() { if (!IsDisposed) { AssetDatabase.StopAssetEditing(); IsDisposed = true; } } }