🐼

UdonSharpでEnumをキャストして使う時の注意点

2024/11/18に公開

はじめに

UdonSharpでEnum値使って計算してて実行時エラーが出たのでその時の調査とか備忘録
この時はuintにキャストして左シフト演算
(別途ulong, byteを使った場合も同じ)

環境

Unity VRChat SDK
2022.3.22f1 3.73

結論

Enum値をuint, ulong, byteにして演算する場合は調査の2の書き方するとよさそう。

調査

書き方を変えてみてエラーが出るもの出ないものを調査

  1. エラーがでるもの1
    シンプルな書き方
    画像のコード
    private void NG1(TestTest arg)
    {
        var val = ((uint)arg) << 1;
    }
  1. OKなもの1
    intキャスト入れてみる
    \textcolor{blue}{これは大丈夫}
    private void OK1(TestTest arg)
    {
        var arg_cast = (int)arg;
        var val = ((uint)arg_cast) << 1;
    }
  1. エラーがでるもの2
    intキャストすればいいのかなと思ってまとめて記載
    \textcolor{red}{ダメ}
    private void NG2(TestTest arg)
    {
        var val = ((uint)((int)arg)) << 1;
    }
  1. OKなもの2
    Enumの問題かint⇒uintのキャストか切り分けたく以下のコード
    普通に通る。それはそう。
    private void OK2(int arg)
    {
        var val = ((uint)arg) << 1;
    }
  1. エラーがでるもの3
    Enum=>uintへのキャストを分けて書いてみる
    \textcolor{red}{ダメ}
    private void NG3(TestTest arg)
    {
        var arg_cast = (uint)arg;
        var val = arg_cast << 1;
    }

調査(それぞれのUdonAssembly)

調査した5例それぞれのUdonAssemblyを見てみる

  1. エラーがでるもの1
    シンプルな書き方
PUSH, __0_arg__param
PUSH, __intnl_SystemUInt32_0
COPY
PUSH, __intnl_SystemUInt32_0
PUSH, __const_SystemInt32_2
PUSH, __lcl_val_SystemUInt32_0
EXTERN, "SystemUInt32.__op_LeftShift__SystemUInt32_SystemInt32__SystemUInt32"
  1. OKなもの1
    intキャスト入れてみる
PUSH, __1_arg__param
PUSH, __lcl_command__SystemInt32_0
COPY
PUSH, __lcl_command__SystemInt32_0
PUSH, __intnl_SystemUInt32_1
EXTERN, "SystemConvert.__ToUInt32__SystemInt32__SystemUInt32"
PUSH, __intnl_SystemUInt32_1
PUSH, __const_SystemInt32_1
PUSH, __lcl_val_SystemUInt32_1
EXTERN, "SystemUInt32.__op_LeftShift__SystemUInt32_SystemInt32__SystemUInt32"
  1. エラーがでるもの2
    intキャストまとめて記載
PUSH, __1_arg__param
PUSH, __intnl_SystemUInt32_1
COPY
PUSH, __intnl_SystemUInt32_1
PUSH, __const_SystemInt32_2
PUSH, __lcl_val_SystemUInt32_1
EXTERN, "SystemUInt32.__op_LeftShift__SystemUInt32_SystemInt32__SystemUInt32"
  1. OKなもの2
PUSH, __3_arg__param
PUSH, __intnl_SystemUInt32_3
EXTERN, "SystemConvert.__ToUInt32__SystemInt32__SystemUInt32"
PUSH, __intnl_SystemUInt32_3
PUSH, __const_SystemInt32_2
PUSH, __lcl_val_SystemUInt32_3
EXTERN, "SystemUInt32.__op_LeftShift__SystemUInt32_SystemInt32__SystemUInt32"
  1. エラーがでるもの3
    Enum=>uintへのキャストを分けて書いてみる
PUSH, __4_arg__param
PUSH, __lcl_arg_cast_SystemUInt32_0
COPY
PUSH, __lcl_arg_cast_SystemUInt32_0
PUSH, __const_SystemInt32_1
PUSH, __lcl_val_SystemUInt32_4
EXTERN, "SystemUInt32.__op_LeftShift__SystemUInt32_SystemInt32__SystemUInt32"

まとめ

書き方次第でUInt32のデータにInt32の値をSystemConvertして格納するのか、Copyして格納するのか、UdonAssemblyが変わる様子。
Enumのintキャストを独立して記載することがミソかも。
(コンパイラのバグかな?)

結論:Enum値をuint, ulong, byteにして演算する場合は、ステップ数は増えるけど一度int変数に格納して使うのが良いかも。

Discussion