| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using UnityEngine.Scripting; |
| | | |
| | | /// <summary> |
| | | /// 为 List<T>.Sort(lambda) / Sort() 提供 AOT 泛型实例化兜底。 |
| | | /// 按 HybridCLR 泛型共享规则,class 引用类型只需实例化 object 版本。 |
| | | /// 若 HeroDebutGiftItem 之类是值类型,需额外添加精确版本。 |
| | | /// 为 List<T>.Sort / Array.Sort 提供 AOT 泛型实例化兜底。 |
| | | /// |
| | | /// 【为什么必须手写】 |
| | | /// List<T>.Sort 运行时会走到 ArraySortHelper<T>、Comparer<T>.Default → GenericComparer<T> |
| | | /// 这些 BCL 内部类,它们的泛型实例化是通过 RuntimeTypeHandle 反射实例化出来的, |
| | | /// 静态扫描器(AOTGenericReferences)永远扫不出来 —— 所以重新生成多少次都没用,必须手写。 |
| | | /// |
| | | /// 【泛型共享规则】 |
| | | /// - 引用类型(class):共享 object 版本,写一个 object 即可覆盖所有引用类型; |
| | | /// - 值类型(struct/enum/int...):不共享,每个用到的值类型都必须在这里精确实例化,否则 iOS 上崩。 |
| | | /// |
| | | /// 【新增排序类型时】:在 Ensure() 里加一行 EnsureSortable<你的值类型>(...) 即可。 |
| | | /// </summary> |
| | | [Preserve] |
| | | public static class AOTRefSort |
| | | { |
| | | // 阻止 IL2CPP 把排序调用当作无副作用而优化掉 |
| | | private static volatile int s_sink; |
| | | |
| | | // 由 Launch.StartGame 调用,防止 IL2CPP 裁剪 |
| | | [Preserve] |
| | | public static void Ensure() |
| | | { |
| | | // Sort(lambda) 完整链路: List.Sort → ArraySortHelper.Sort → Comparison.Invoke |
| | | var list = new List<object> { new object(), new object() }; |
| | | list.Sort((a, b) => 0); |
| | | // 引用类型:object 版本覆盖所有 class(含自定义类、string 等) |
| | | EnsureSortable<object>(new object(), new object()); |
| | | |
| | | // Sort() 无参: 需要 IComparable,用 string(class → 共享 object) |
| | | var list2 = new List<string> { "b", "a" }; |
| | | list2.Sort(); |
| | | // 值类型:项目里实际 Sort 的主要是 List<int>,值类型不共享须精确实例化 |
| | | EnsureSortable<int>(1, 0); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 精确实例化类型 T 的整条排序调用链: |
| | | /// Sort() / Sort(Comparison) / Sort(IComparer) / Array.Sort / Comparer<T>.Default。 |
| | | /// 传两个不同的样本值,保证列表长度 > 1,真正走进内部 IntrospectiveSort。 |
| | | /// </summary> |
| | | [Preserve] |
| | | private static void EnsureSortable<T>(T a, T b) |
| | | { |
| | | // Sort(Comparison<T>) → ArraySortHelper<T>.Sort(Span<T>, Comparison<T>) |
| | | var list = new List<T> { a, b }; |
| | | list.Sort((x, y) => 0); |
| | | |
| | | // Sort(IComparer<T>) + Sort() → Comparer<T>.Default → GenericComparer<T>/ObjectComparer<T> |
| | | var cmp = Comparer<T>.Default; |
| | | list.Sort(cmp); |
| | | list.Sort(); |
| | | |
| | | // Array.Sort<T> 的三条常用重载 |
| | | var arr = new T[] { a, b }; |
| | | Array.Sort(arr); |
| | | Array.Sort(arr, (x, y) => 0); |
| | | Array.Sort(arr, cmp); |
| | | |
| | | s_sink += list.Count + arr.Length; |
| | | } |
| | | } |