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;
}
}
}