9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unityの C# のSortでハマった話

Last updated at Posted at 2024-03-06

ある日、デバッガから「岩崎さん、ハングアップします」とレポートが上がってきた。
レポートに貼ってあるログを見ると…

NullReferenceException: Object reference not set to an instance of an object
HogehogeManager+<>c.<Gethogehoge>b__45_2 (HogeEntity a, HogeEntity b) (at Assets/Scripts/Battle/HogehogeManager.cs:448)
System.Collections.Generic.ArraySortHelper`1[T].PickPivotAndPartition (T[] keys, System.Int32 lo, System.Int32 hi, System.Comparison`1[T] comparer) (at <b89873cb176e44a995a4781c7487d410>:0)
System.Collections.Generic.ArraySortHelper`1[T].IntroSort (T[] keys, System.Int32 lo, System.Int32 hi, System.Int32 depthLimit, System.Comparison`1[T] comparer) (at 

「は?」 なんでSortがnull吐いてんのよ?
となって、調べると、落ちているのはなんと、こんなSort。

List<T>.Sort((a, b) => ((a.x - b.x)>0)?1:-1 );

どうして落ちているのかさっぱりわからず、でも試すと、確かに特定条件下でnullを吐く。
しょうがないので、とりあえずノームソートを書いて、それだと落ちないのを確認したのち、ふっと気がついた。
「まさかとは思うけれど、ラムダ式の書き方で落ちる?」
で、ラムダ式を以下に書き換えてみた。

List<T>.Sort((a, b) => ((a.x.CompareTo(b.x) );

なんてこったい、落ちなくなったぞ!?
なんでや!? と、調べていくと、stackoverflowのこのスレッドに当たった。

で、読むと、端的に書けば比較関数に一貫性がないとNull で落ちるという話が書かれている。
でも、 a.x > b.x ? 1:-1 のどこに一貫性がないなんてことがあんだよ…と、考えていて気がついた。
a.x == b.x のとき、 a.x>b.xb.x>a.xどっちも-1を返す 、すなわち一貫性がない、だからnull落ちしてたんだ!
と、気がついて、理由が腹落ちしたところに、この話をslackのスレッドで展開してたところ、スーパー出来る同僚が曰く。

てか、List<T>.Sort((a, b) => (a.x - b.x) だけでOKでは…
正負または0を返せばいいだけで、-1/1に限定する必要はない

ガ━━(;゚Д゚)━( ゚Д)━(  ゚)━(   )━(゚;  )━(Д゚; )━(゚Д゚;)━━ン!!!!!
俺って、バカ。
というわけで、教訓。

  • UnityのC#のSortは比較関数が一貫性のない値を返すとnull落ちする。そしてこれはとてもわかりにくい
  • だいたいSortを1/0/-1に限定する必要はない
  • コメントでこれはmonoの古い目のやつのバグだと思うという話があったのでUnityの、に限定しておきました
  • なお、出ているソースはもちろん「そのまま」ではないのはご了承くださいw
9
8
3

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
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?