【Unity】インターフェースのデフォルト実装はビルド後の動作が違う話

対象読者

  • UnityのWebGLでのビルド後の動作が変わって困っている人

記事の内容

  • 特定の条件下でインターフェースのデフォルト実装を使用したとき、WebGLビルド後の動作が変わる原因の解説をする

実際に問題が発生するコード


public interface IHogeValue
{
   int Value { get; set; }

   int GetValue()
   {
      return Value;
   }
}

public class HogeParent : IHogeValue
{
   public int Value { get; set; }

   public HogeParent()
   {
      Value = 1;
   }
}

public class HogeChild : HogeParent, IHogeValue
{
   new public int Value { get; set; }

   public HogeChild()
   {
      Value = 2;
   }

}

public class Logger : MonoBehaviour
{
   void Start()
   {
      IHogeValue child = new HogeChild();
      Debug.Log(child.GetValue());
      Debug.Log(((IHogeValue)child).GetValue());
      Debug.Log(child.Value);
      Debug.Log(((IHogeValue)child).Value);
      Debug.Log(((HogeParent)child).Value);
   }
}

実際に動作させると、Loggerの出力結果は、Windowsビルドの場合は「1 1 2 1 1」、WebGLビルドの場合は「2 1 2 1 1」となります。

2つのビルドにおいて、変数「child」が保持している変数の値は同じで、プロパティから呼び出しても動作は同じだけど、関数からプロパティを呼びだしときだけ、動作が変わります。

予防法

  • 曖昧なプロパティを作らない

今回の場合だと、「HogeChildのValue」が曖昧なプロパティです。

このプロパティを消すと、WindowsとWebGLで動作は同じになります。

問題が発生する条件

  • 子クラスと親クラスに付けられたinterfaceは異なるが、同名の関数を持っている
  • 継承しているinterfaceにデフォルト実装がされている
  • 同名関数内で同名プロパティを使った処理をする
  • 子クラスから、その関数を呼び出す

まとめ

  • WebGLビルドをするなら、インターフェースのデフォルト実装の使い方に注意
  • 普通の書き方をすれば、殆ど問題は発生しない
  • 特殊な書き方をしても、「曖昧な関数やプロパティ」を消す事で問題が解消できる場合がある