[Unity][ILRuntime][C#]热更新中数组Dictionary通过value获得key

这篇博客主要探讨了在Unity使用ILRuntime进行热更新时,如何处理C# Dictionary类型的数据。由于Dictionary的灵活性,作者提到了在热更新环境中通过FirstOrDefault方法减少冗余代码的需求,但指出此方法需要在ILRuntime中注册。文章引用了Unity编辑器的错误信息,并提供了ILRuntimeWrapper.cs文件的相关内容,以及针对热更新报错的解决办法,特别是当涉及通过Dictionary值获取键的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Unity编辑器报错

KeyNotFoundException: Cannot find Delegate Adapter for:scienceTree/<>c__DisplayClass15_0.<click>b__1(KeyValuePair`2 q), Please add following code:
appdomain.DelegateManager.RegisterFunctionDelegate<System.Collections.Generic.KeyValuePair<ILRuntime.Runtime.Intepreter.ILTypeInstance, FairyGUI.GButton>, System.Boolean>();

参考资料1

由于Dictionary<T,T1>太过灵活,T什么类型的类都可以,通过FirstOrDefault减少冗余代码。

但是FirstOrDefault在热更新中得注册。

...
using FairyGUI;
using System.Linq;//FirstOrDefault
...
if (dict.ContainsValue(gb))
            {
                Debug.Log("click  item3:" + gb.id + "/name:" + gb.name + "/");
                //dict.
                //var keys = dict.Where(q => q.Value == gb).Select(q => q.Key);
                var firstKey = dict.FirstOrDefault(q => q.Valu
<think>好的,用户问的是C#Dictionary如何按顺序获取value的值。首先,我需要回想一下Dictionary的基本特性。DictionaryC#中是哈希表实现的,所以它本身是无序的,这应该是用户遇到问题的关键点。用户可能在使用Dictionary时,发现遍历出来的顺序和添加的顺序不一致,或者想要按照某种特定的顺序来获取值,比如插入顺序或者键的排序。 接下来,我需要考虑用户可能的实际应用场景。比如用户可能在处理配置文件、游戏数据或者需要保持顺序的键值对时遇到了问题。例如,在Unity中,可能需要按照对象被创建的顺序来处理它们,或者需要根据键的字母顺序来显示数据。 然后,用户的需求是“按顺序获取value的值”。这里的顺序可能包括插入顺序、键的排序或者自定义排序。这时候,我需要提供几种不同的解决方案,并比较它们的优缺点。首先想到的是使用OrderedDictionary,但C#原生的OrderedDictionary是非泛型的,可能不太方便。另一个选择是使用SortedDictionary,但它会根据键来排序,而不是插入顺序。所以可能需要结合其他方法,比如使用List来维护顺序,或者使用Linq的OrderBy来排序。 还需要考虑用户可能对性能有要求,特别是在处理大量数据时。例如,使用List和Dictionary结合的方法虽然可以保持插入顺序,但每次添加元素需要维护两个集合,可能会有额外的内存开销。而使用Linq排序可能在每次获取时都需要重新排序,影响性能。 另外,用户可能在代码中已经使用了Dictionary,现在需要修改为有序的结构,所以需要给出兼容现有代码的解决方案。比如,使用Linq进行临时排序,而无需改变原有数据结构,这样改动最小,但每次获取时都需要排序。或者,建议用户改用SortedDictionary或SortedList,如果顺序是关键需求的话。 还需要检查是否有其他可能的解决方案,比如第三方库或者更高级的数据结构,但考虑到用户可能希望使用C#原生支持的方法,所以主要集中在内置的类库上。 最后,需要总结各种方法的适用场景,帮助用户根据具体情况选择最合适的方案。例如,如果需要保持插入顺序,可以使用List配合Dictionary;如果需要按键排序,可以使用SortedDictionary;如果只是临时需要排序,可以使用Linq的OrderBy。</think>在 C# 中,`Dictionary<TKey, TValue>` **默认不保证存储顺序**(底层基于哈希表实现),若需要按顺序获取值,需通过特定方法处理。以下是 **5 种实现方案**,按使用场景分类: --- ### **方案 1:使用有序集合替代(推荐)** #### 📌 若需严格保持 **插入顺序** ```csharp // 使用 System.Collections.Specialized 命名空间中的 OrderedDictionary var orderedDict = new OrderedDictionary(); orderedDict.Add("Key1", 100); orderedDict.Add("Key2", 200); // 按插入顺序遍历 foreach (DictionaryEntry entry in orderedDict) { Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}"); } ``` - ✅ 优点:原生支持插入顺序 - ⚠️ 缺点:非泛型,需装箱拆箱操作 --- ### **方案 2:通过 LINQ 排序获取** #### 📌 按 **键的顺序** 获取值 ```csharp Dictionary<string, int> dict = new Dictionary<string, int> { {"Apple", 5}, {"Banana", 3}, {"Cherry", 7} }; // 按键升序获取值 var orderedValues = dict.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value); foreach (int val in orderedValues) { Console.WriteLine(val); // 输出 5,3,7(按字母顺序 Apple→Banana→Cherry) } // 按值排序 var valuesByNumber = dict.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Value); ``` - 🔧 扩展:使用 `OrderByDescending` 反向排序 - 💡 技巧:可通过 `ThenBy` 实现多级排序 --- ### **方案 3:自定义键顺序列表** #### 📌 需 **预定义顺序** 且频繁访问 ```csharp // 定义独立的有序键集合 List<string> keyOrder = new List<string> {"Second", "First", "Third"}; Dictionary<string, int> dict = new Dictionary<string, int> { {"First", 1}, {"Second", 2}, {"Third", 3} }; // 按自定义顺序获取值 foreach (string key in keyOrder) { if (dict.TryGetValue(key, out int value)) { Console.WriteLine(value); // 输出 2 → 1 → 3 } } ``` - ✅ 适用场景:固定顺序的配置数据 - 🔒 注意:需手动维护键列表与字典的同步 --- ### **方案 4:使用 SortedDictionary** #### 📌 需要 **自动按键排序** ```csharp using System.Collections.Generic; SortedDictionary<string, int> sortedDict = new SortedDictionary<string, int> { {"Zebra", 5}, {"Apple", 2}, {"Mango", 8} }; // 自动按键升序排列 foreach (KeyValuePair<string, int> kvp in sortedDict) { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); // 输出顺序 Apple → Mango → Zebra } ``` - ⚠️ 注意:性能比普通 Dictionary 略低(基于红黑树实现) - 🔄 对比:`SortedList<TKey, TValue>` 更适合频繁按索引访问的场景 --- ### **方案 5:混合存储(字典+列表)** #### 📌 需同时保持 **快速查找和插入顺序** ```csharp public class OrderedDictionaryWrapper<TKey, TValue> { private readonly Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>(); private readonly List<TKey> _orderKeys = new List<TKey>(); public void Add(TKey key, TValue value) { _dict.Add(key, value); _orderKeys.Add(key); } public IEnumerable<TValue> GetValuesInOrder() { return _orderKeys.Select(key => _dict[key]); } } // 使用示例 var wrapper = new OrderedDictionaryWrapper<string, int>(); wrapper.Add("Dog", 10); wrapper.Add("Cat", 5); foreach (int val in wrapper.GetValuesInOrder()) // 保持插入顺序 { Console.WriteLine(val); // 输出 10 → 5 } ``` - ✅ 优点:查询复杂度仍为 O(1) - 💡 扩展:可添加按索引访问功能 --- ### **性能对比表** | 方法 | 时间复杂度 | 空间复杂度 | 顺序类型 | |-----------------------|------------|------------|----------------| | OrderedDictionary | O(1) 查找 | O(n) | 插入顺序 | | LINQ 排序 | O(n log n) | O(n) | 动态排序 | | SortedDictionary | O(log n) | O(n) | 自动键排序 | | 混合存储(字典+列表) | O(1) 查找 | O(2n) | 自定义/插入顺序 | --- ### **特殊场景处理** #### 1. 遍历时动态修改顺序 ```csharp // 使用中间列表避免迭代时修改异常 var tempKeys = dict.Keys.ToList(); foreach (var key in tempKeys.OrderBy(k => k)) { // 安全操作 } ``` #### 2. 线程安全有序访问 ```csharp using System.Collections.Concurrent; var concurrentDict = new ConcurrentDictionary<string, int>(); var orderedValues = new ConcurrentQueue<int>(); Parallel.ForEach(dict, kvp => { orderedValues.Enqueue(kvp.Value); }); ``` --- ### **Unity 引擎中的优化技巧** ```csharp // 预分配内存避免GC public class PreallocatedDictionary<TKey, TValue> { private Dictionary<TKey, TValue> _dict; private TValue[] _cachedValuesArray; public void Prepare(int capacity) { _dict = new Dictionary<TKey, TValue>(capacity); _cachedValuesArray = new TValue[capacity]; } public TValue[] GetValuesInOrder() { int i = 0; foreach (var kvp in _dict.OrderBy(k => k.Key)) { _cachedValuesArray[i++] = kvp.Value; } return _cachedValuesArray; } } ``` 根据需求选择最适合的方案,若需高频访问有序数据,推荐 **方案5 混合存储**;若仅需临时排序,使用 **LINQ** 最为便捷。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值