LoginSignup
0
0

More than 3 years have passed since last update.

UnityのIL2CPPとDataContractJsonSerializerを用いたシリアライズの組み合わせの罠

Last updated at Posted at 2021-01-30

この記事で述べていること

・Unityのビルド時にIL2CPPを使い、かつDataContractJsonSerializerのWriteObjectでインスタンスのJsonデータをStreamに書き込もうとすると、ビルド環境でランタイムエラー(System.NullReferenceException)が発生する。

・そのまま回避する方法はtry-catchでエラーを握りつぶすしかない(要検証)ので、これを使うのならMonoでのビルドを使うこと。

Unityのバージョン

Unity 2018.4.5f1

はじめに

ある日私はUnityで、ある構造体のインスタンスをシリアライズしてファイルに書き出し保存しようと考えました。

最初はJsonSerializerを使おうと考えたのですが、名前空間System.Text.Jsonが入っていないらしいためやめ、代わりとしてSystem.Runtime.Serialization.JsonDataContractJsonSerializerを以下のように用いようとしたのですが、そこで問題が発生しました。

やったことのコード例
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

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0