この記事で述べていること
・Unityのビルド時にIL2CPPを使い、かつDataContractJsonSerializerのWriteObjectでインスタンスのJsonデータをStreamに書き込もうとすると、ビルド環境でランタイムエラー(System.NullReferenceException
)が発生する。
・そのまま回避する方法はtry-catchでエラーを握りつぶすしかない(要検証)ので、これを使うのならMonoでのビルドを使うこと。
Unityのバージョン
Unity 2018.4.5f1
はじめに
ある日私はUnityで、ある構造体のインスタンスをシリアライズしてファイルに書き出し保存しようと考えました。
最初はJsonSerializer
を使おうと考えたのですが、名前空間System.Text.Json
が入っていないらしいためやめ、代わりとしてSystem.Runtime.Serialization.Json
のDataContractJsonSerializer
を以下のように用いようとしたのですが、そこで問題が発生しました。
public class Hoge : MonoBehaviour{
//Dataの構造体の定義
[DataContract]
public struct Data{
[DataMenber]
public int hoge;
}
//Dataのインスタンス
private Data data;
//データのインスタンスのシリアライズを行う
private void serializeData(){
using(var memoryStream = new MemoryStream()){
var dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Data));
//memoryStreamにDataのインスタンスをシリアライズしたJsonデータを書き込む
//ここで問題が発生しました
dataContractJsonSerializer.WriteObject(memoryStream, data);
//カーソル位置を最初に戻す
memoryStream.Position = 0;
//memoryStreamの内容を読み込んで、全ての文字列をファイルに書き出す
using(var streamReader = new StreamReader(memoryStream, Encoding.UTF8)){
var filePath = "任意のファイルのパス";
File.WriteAllText(filePath, streamReader.ReadToEnd(), Encoding.UTF8);
}
}
}
}
起こった問題
Unityエディタ環境では上のコードはエラーも無く動いたのですが、ビルド後のexeで見てみるとうまく動かないことが判明しました。
ビルド後の環境のためDebug.Log()
は使えないので、テキストをログ代わりにしてプリントデバッグしたところ、WriteObjectでインスタンスをシリアライズして書き込む段階で止まっていることがわかりました。
そのためtry-catchで囲んでエラーを出力してみると、NullReferenceException
が出ていることが判明しましたが、 当然ながらmemoryStream、dataContractJsonSerializerどちらもnullチェックをしてもfalseであった(構造体は非null許容型ですし)ため、他のビルドに関わる部分を調べてみることにしました。
原因
ビルド時のPlayerSettingsで、ConfigurationのScripting BackendをIL2CPPにしていることが原因でした。
解決法
原因から分かると思いますが、Monoに切り替えたところ正常に動きました。
IL→C++への変換でうまくいかないところがあるのでしょうか。はっきり言ってよく分かりません。
この記事を見た人へのお願い
上記のようにとりあえずの解決法は見つかりましたが、原因については全く分かっていない状態です。
異なる解決法(IL2CPPのままでOKなものなど)、もしくは原因の具体的な詳細など分かる方がおられるなら、コメント・Twitter等で教えていただけるとありがたいです。
参考文献
・Microsoft Docs JsonSerializer
https://docs.microsoft.com/ja-jp/dotnet/api/system.text.json.jsonserializer?view=net-5.0
・Microsoft Docs DataContractJsonSerializer
https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.serialization.json.datacontractjsonserializer?view=net-5.0