IL2CPPでLINQのAOTエラーが結構改善されたような気がする

# IL2CPPでLINQのAOTエラーが結構改善されたような気がする #
という話

以下の記事の通りかわいいかわいいLINQちゃんはiOSだと気をつけて使わないとクラッシュする。
と言う問題がMonoの時にはありました。
[Unity + iOSのAOTでの例外の発生パターンと対処法](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjuxY65u4vLAhXhhaYKHeXCCVsQFggcMAA&url=http%3A%2F%2Fneue.cc%2F2014%2F07%2F01_474.html&usg=AFQjCNFDsJBvfgNBHQ32r9jqadJEIr6Pwg&sig2=ciXUffa5YX67_rzEeIkR9A)とか
[Unity+iOSでエラーになるLINQのまとめ - Qiita](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cad=rja&uact=8&ved=0ahUKEwjuxY65u4vLAhXhhaYKHeXCCVsQFggjMAE&url=http%3A%2F%2Fqiita.com%2FRyotaMurohoshi%2Fitems%2F6fb02e50d9e08b487f47&usg=AFQjCNFGKc8ZIjz1-rOydVBO3oxt3ub2AA&sig2=Uksdvt7qkN2PD7TJ0k8oyw)

どうやらIL2CPPになった段階で結構解消されたような気がするので、テストコード書いてみてクラッシュするかなー？しないかなー？って確認したところ以下のメソッドは全部AOTで**クラッシュしません**でした。(手元の環境はXcode7,iOS9,Unity5.3.2p3で確認)

[Unity+iOSでエラーになるLINQのまとめ - Qiita](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cad=rja&uact=8&ved=0ahUKEwjuxY65u4vLAhXhhaYKHeXCCVsQFggjMAE&url=http%3A%2F%2Fqiita.com%2FRyotaMurohoshi%2Fitems%2F6fb02e50d9e08b487f47&usg=AFQjCNFGKc8ZIjz1-rOydVBO3oxt3ub2AA&sig2=Uksdvt7qkN2PD7TJ0k8oyw)
を参考に以下のクラッシュしていたメソッドのみ検証です。


* Average
* Max
* Min
* Sum
* FirstOrDefault
* Last
* LastOrDefault
* Single
* SingleOrDefault
* ToDictionary
* ToLookup
* Join
* OrderBy
* OrderByDescending


クラッシュ本当にしないのかは検証不足なのですが、なんかいい感じに解決してそうなので公開しておきます。（だれか追試してー）

```csharp

using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;

public struct SimpleStruct{
	public int Value{get;set;}
	public SimpleStruct(int value):this(){
		Value = value;
	}
}

public class SimpleClass{
	public int Value{get;set;}
	public SimpleClass(int value){
		Value = value;
	}
}

public class AOTTest : MonoBehaviour {

	void OnGUI()
	{
		if(GUILayout.Button("Test Average"))
		{
			var ave = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).Select(s => s.Value).Average();
			Debug.Log("Average:" + ave);
		}

		if(GUILayout.Button("Test Max"))
		{
			var max = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Max();
			Debug.Log("Max:" + max);
		}

		if(GUILayout.Button("Test Min"))
		{
			var min = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Min();
			Debug.Log("Min:" + min);
		}

		if(GUILayout.Button("Test Sum"))
		{
			var sum = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Sum();
			Debug.Log("Sum:" + sum);
		}

		if(GUILayout.Button("Test FirstOrDefault"))
		{
			var first = new int[10].Select(_=>Random.Range(0,1000)).FirstOrDefault();
			Debug.Log("First:" + first);
		}

		if(GUILayout.Button("Test Last"))
		{
			var last = new int[10].Select(_=>Random.Range(0,1000)).Last();
			Debug.Log("Last:" + last);
		}

		if(GUILayout.Button("Test LastOrDefault"))
		{
			var last = new int[10].Select(_=>Random.Range(0,1000)).LastOrDefault();
			Debug.Log("LastOrDefault:" + last);
		}

		if(GUILayout.Button("Test Single"))
		{
			var value = new int[10].Select((i,n)=>n).Take(1).Single();
			Debug.Log("Single:" + value);
		}

		if(GUILayout.Button("Test SingleOrDefault"))
		{
			var value = new bool[10].Select((i,n)=>n).Take(1).SingleOrDefault();
			Debug.Log("SingleOrDefault:" + value);
		}

		if(GUILayout.Button("Test Join"))
		{
			var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToArray();
			var dic = a.Join(a,i=>i.Value,o => o.Value,(i,o)=> i.Value + o.Value).ToArray();
			Debug.Log (dic);
        }
        

		if(GUILayout.Button("Test ToDictionary 1"))
		{
			var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToDictionary (skill => skill.Value);
			DictionaryLog(dic);
		}

		if(GUILayout.Button("Test ToDictionary 2"))
		{
			var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToDictionary (skill => skill.Value,EqualityComparer<int>.Default);
			DictionaryLog(dic);
		}

		if(GUILayout.Button("Test ToLookup 1"))
		{
			var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToLookup (skill => skill.Value);
			LookupLog(dic);
		}
		
		if(GUILayout.Button("Test ToLookup 2"))
		{
			var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToLookup (skill => skill.Value,EqualityComparer<int>.Default);
			LookupLog(dic);
		}

		if(GUILayout.Button("Test OrderBy")){
			var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).OrderBy( k => k.Value);
			foreach (var item in a) {
				Debug.Log("Sort"+item.Value);
			}
		}

		if(GUILayout.Button("Test OrderByDescending")){
			var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).OrderByDescending( k => k.Value);
			foreach (var item in a) {
				Debug.Log("Sort"+item.Value);
            }
        }
        
    }

	private void DictionaryLog<K,T>(Dictionary<K,T> dict)
	{
		foreach(var kv in dict)
		{
			Debug.Log(kv.Key + ":" + kv.Value);
		}
	}

	private void LookupLog<K,T>(ILookup<K,T> dict)
	{
		foreach(var kv in dict)
		{
			Debug.Log(kv.Key + ":" + kv.ToArray());
		}
	}



}



```

こういう書捨てのコード書くときレガシーGUI便利だと思います。

## やってないこと ##
* 他のメソッドが死んでないかのテスト
* 他のバージョンでのテスト