重排序?qū)崙?zhàn):從原理到性能優(yōu)化)
1. 項(xiàng)目概述為什么Unity開發(fā)者必須掌握List排序在Unity游戲開發(fā)中我們幾乎每天都在和ListT打交道。無論是管理游戲中的敵人列表、背包里的道具、排行榜上的玩家數(shù)據(jù)還是UI界面中動(dòng)態(tài)生成的元素List都是最核心的數(shù)據(jù)容器之一。然而很多開發(fā)者尤其是剛?cè)腴T的伙伴往往只停留在Add、Remove和foreach循環(huán)的層面當(dāng)遇到“按戰(zhàn)斗力從高到低排序戰(zhàn)斗力相同則按等級(jí)從高到低等級(jí)再相同則按注冊(cè)時(shí)間從早到晚”這類復(fù)雜排序需求時(shí)就容易陷入手寫復(fù)雜循環(huán)比較、代碼冗長且難以維護(hù)的困境。這正是“多條件權(quán)重排序”與“自定義類排序”要解決的痛點(diǎn)。想象一下你正在開發(fā)一款MMORPG的游戲排行榜系統(tǒng)。一個(gè)簡單的list.Sort()顯然無法處理這種多維度、有權(quán)重的排序邏輯。如果你手動(dòng)去實(shí)現(xiàn)冒泡或選擇排序不僅效率低下而且每增加一個(gè)排序條件代碼就要大改一次耦合度極高。而Unity C#提供的List.Sort方法配合ComparisonT委托、IComparableT接口以及強(qiáng)大的LINQ能夠讓我們以聲明式、高可讀性的方式優(yōu)雅地解決這些復(fù)雜排序問題。掌握這些技巧意味著你能寫出更健壯、更易擴(kuò)展的業(yè)務(wù)邏輯代碼這在面試和實(shí)際項(xiàng)目協(xié)作中都是一個(gè)非常加分的亮點(diǎn)。2. 核心思路拆解理解排序的“游戲規(guī)則”在深入代碼之前我們必須先厘清幾個(gè)核心概念這就像在開始游戲前先讀懂規(guī)則手冊(cè)。2.1 排序的本質(zhì)比較與交換無論排序算法多么復(fù)雜其核心無非是兩步比較兩個(gè)元素的“大小”然后根據(jù)比較結(jié)果決定是否交換它們的位置。在C#中這個(gè)“比較”的行為被抽象為“比較器”。對(duì)于ListT.Sort()方法它需要知道如何比較兩個(gè)T類型的對(duì)象。我們可以通過三種主流方式來告訴它默認(rèn)比較器如果T類型本身實(shí)現(xiàn)了IComparableT接口如int,float,stringSort()會(huì)使用其內(nèi)置的CompareTo方法。委托比較器傳入一個(gè)ComparisonT委托這是一個(gè)函數(shù)指針指向一個(gè)你自己定義的、接收兩個(gè)T參數(shù)并返回整數(shù)的方法。接口比較器傳入一個(gè)實(shí)現(xiàn)了IComparerT接口的類的實(shí)例。這個(gè)接口要求實(shí)現(xiàn)一個(gè)Compare(T x, T y)方法。多條件權(quán)重排序本質(zhì)上就是在這個(gè)“比較”函數(shù)中按照我們?cè)O(shè)定的優(yōu)先級(jí)規(guī)則依次比較多個(gè)字段。2.2 權(quán)重排序的邏輯優(yōu)先級(jí)隊(duì)列的思維“權(quán)重”意味著不同條件的重要性不同。在代碼實(shí)現(xiàn)時(shí)我們通常采用瀑布式比較邏輯。以排行榜為例偽代碼如下比較函數(shù)(玩家A 玩家B): 1. 先比較戰(zhàn)斗力主權(quán)重 - 如果 A.戰(zhàn)斗力 B.戰(zhàn)斗力 返回 1 (表示A應(yīng)排在B前面) - 如果 A.戰(zhàn)斗力 B.戰(zhàn)斗力 返回 -1 (表示A應(yīng)排在B后面) - 如果相等進(jìn)入下一步 2. 再比較等級(jí)次權(quán)重 - 如果 A.等級(jí) B.等級(jí) 返回 1 - 如果 A.等級(jí) B.等級(jí) 返回 -1 - 如果相等進(jìn)入下一步 3. 最后比較注冊(cè)時(shí)間末權(quán)重 - 如果 A.注冊(cè)時(shí)間 B.注冊(cè)時(shí)間 (越早注冊(cè)越靠前) 返回 1 - 如果 A.注冊(cè)時(shí)間 B.注冊(cè)時(shí)間 返回 -1 - 如果還相等返回 0 (表示兩者順序任意)這種邏輯清晰地將多條件排序分解為一系列單條件排序高級(jí)別條件“一票否決”低級(jí)別條件。2.3 自定義類的挑戰(zhàn)與機(jī)遇對(duì)于我們自己定義的類比如Player、ItemC#并不知道如何比較它們。我們必須顯式地提供比較邏輯。這既是挑戰(zhàn)需要額外編碼也是機(jī)遇我們可以定義任何有意義的比較規(guī)則。通過實(shí)現(xiàn)IComparablePlayer接口我們可以讓Player類自己知道如何與另一個(gè)Player比較這使得排序代碼players.Sort()變得極其簡潔和自然是面向?qū)ο笤O(shè)計(jì)思想的良好體現(xiàn)。3. 實(shí)戰(zhàn)演練從簡單到復(fù)雜的四種排序方法理論說得再多不如一行代碼。我們創(chuàng)建一個(gè)Player類作為示例并準(zhǔn)備一些測試數(shù)據(jù)。using System; using System.Collections.Generic; // 自定義玩家類 public class Player { public string Name { get; set; } public int CombatPower { get; set; } // 戰(zhàn)斗力 public int Level { get; set; } // 等級(jí) public DateTime JoinTime { get; set; } // 注冊(cè)時(shí)間 public Player(string name, int power, int level, DateTime joinTime) { Name name; CombatPower power; Level level; JoinTime joinTime; } public override string ToString() { return ${Name} (戰(zhàn)力:{CombatPower}, 等級(jí):{Level}, 加入:{JoinTime:yyyy-MM-dd}); } } class Program { static void Main(string[] args) { ListPlayer players new ListPlayer { new Player(張三, 8500, 45, new DateTime(2023, 5, 10)), new Player(李四, 9200, 50, new DateTime(2023, 3, 15)), new Player(王五, 9200, 48, new DateTime(2023, 4, 1)), new Player(趙六, 7800, 50, new DateTime(2023, 6, 20)), new Player(孫七, 9200, 50, new DateTime(2023, 2, 28)), // 與李四戰(zhàn)力等級(jí)相同但更早注冊(cè) }; // 后續(xù)的排序演示將基于這個(gè)players列表進(jìn)行 } }我們的目標(biāo)將玩家列表按**戰(zhàn)斗力降序、等級(jí)降序、注冊(cè)時(shí)間升序越早越靠前**的規(guī)則排序。3.1 方法一使用匿名方法與Comparison委托最靈活這是最常用、最直觀的方式特別適合臨時(shí)性的、邏輯簡單的排序。// 使用匿名方法 players.Sort(delegate(Player x, Player y) { // 1. 比較戰(zhàn)斗力降序 int powerCompare y.CombatPower.CompareTo(x.CombatPower); // 注意y和x的順序?qū)崿F(xiàn)降序 if (powerCompare ! 0) return powerCompare; // 2. 比較等級(jí)降序 int levelCompare y.Level.CompareTo(x.Level); if (levelCompare ! 0) return levelCompare; // 3. 比較注冊(cè)時(shí)間升序 return x.JoinTime.CompareTo(y.JoinTime); }); // 使用Lambda表達(dá)式更簡潔推薦 players.Sort((x, y) { int powerCompare y.CombatPower.CompareTo(x.CombatPower); if (powerCompare ! 0) return powerCompare; int levelCompare y.Level.CompareTo(x.Level); if (levelCompare ! 0) return levelCompare; return x.JoinTime.CompareTo(y.JoinTime); }); // 輸出結(jié)果 Console.WriteLine( 使用Lambda表達(dá)式排序結(jié)果 ); foreach (var p in players) { Console.WriteLine(p); }輸出結(jié)果 使用Lambda表達(dá)式排序結(jié)果 孫七 (戰(zhàn)力:9200, 等級(jí):50, 加入:2023-02-28) // 戰(zhàn)力最高等級(jí)最高且注冊(cè)最早 李四 (戰(zhàn)力:9200, 等級(jí):50, 加入:2023-03-15) // 戰(zhàn)力等級(jí)同孫七但注冊(cè)較晚 王五 (戰(zhàn)力:9200, 等級(jí):48, 加入:2023-04-01) // 戰(zhàn)力同前兩者但等級(jí)較低 張三 (戰(zhàn)力:8500, 等級(jí):45, 加入:2023-05-10) // 戰(zhàn)力次之 趙六 (戰(zhàn)力:7800, 等級(jí):50, 加入:2023-06-20) // 戰(zhàn)力最低注意CompareTo方法返回值的含義是固定的當(dāng)前實(shí)例小于參數(shù)返回-1等于返回0大于返回1。為了實(shí)現(xiàn)降序我們巧妙地調(diào)換了y.CompareTo(x)的順序。這是實(shí)現(xiàn)升降序的關(guān)鍵技巧。3.2 方法二實(shí)現(xiàn)IComparable接口使類自帶排序能力如果某個(gè)類有一種“自然的”、“默認(rèn)的”排序規(guī)則比如學(xué)生按學(xué)號(hào)、商品按價(jià)格那么實(shí)現(xiàn)IComparableT接口是更面向?qū)ο蟮倪x擇。這會(huì)讓排序調(diào)用變得無比簡潔。// 修改Player類實(shí)現(xiàn)IComparablePlayer public class Player : IComparablePlayer { // ... 屬性定義同上 ... // 實(shí)現(xiàn)CompareTo方法定義默認(rèn)排序規(guī)則戰(zhàn)力降序-等級(jí)降序-注冊(cè)時(shí)間升序 public int CompareTo(Player other) { if (other null) return 1; // 約定非空對(duì)象大于空對(duì)象 // 戰(zhàn)斗力降序比較 int powerCompare other.CombatPower.CompareTo(this.CombatPower); if (powerCompare ! 0) return powerCompare; // 等級(jí)降序比較 int levelCompare other.Level.CompareTo(this.Level); if (levelCompare ! 0) return levelCompare; // 注冊(cè)時(shí)間升序比較 return this.JoinTime.CompareTo(other.JoinTime); } } // 使用方式一行代碼搞定排序 players.Sort(); // 直接調(diào)用無參數(shù)的Sort()將使用Player類中定義的CompareTo規(guī)則 Console.WriteLine( 實(shí)現(xiàn)IComparable接口排序結(jié)果 ); foreach (var p in players) { Console.WriteLine(p); }實(shí)操心得優(yōu)點(diǎn)代碼極度簡潔players.Sort()語義清晰體現(xiàn)了類的封裝性。適合作為類的“默認(rèn)”排序規(guī)則。缺點(diǎn)一個(gè)類只能有一種“默認(rèn)”排序規(guī)則。如果你還需要“按等級(jí)升序”或者“純按名字排序”等其他規(guī)則這個(gè)方法就無能為力了。此時(shí)我們需要更靈活的IComparer。3.3 方法三創(chuàng)建獨(dú)立的IComparer類高復(fù)用性與靈活性當(dāng)我們需要多種不同的排序規(guī)則時(shí)創(chuàng)建獨(dú)立的比較器類是最佳實(shí)踐。它符合“單一職責(zé)原則”并且可以在項(xiàng)目各處復(fù)用。// 創(chuàng)建一個(gè)比較器專門按“等級(jí)升序、戰(zhàn)斗力升序”排序 public class LevelAscendingComparer : IComparerPlayer { public int Compare(Player x, Player y) { if (x null y null) return 0; if (x null) return -1; // 約定空對(duì)象排在最前 if (y null) return 1; // 1. 等級(jí)升序 int levelCompare x.Level.CompareTo(y.Level); if (levelCompare ! 0) return levelCompare; // 2. 戰(zhàn)斗力升序 return x.CombatPower.CompareTo(y.CombatPower); } } // 創(chuàng)建另一個(gè)比較器專門按“名字字典序”排序 public class NameComparer : IComparerPlayer { public int Compare(Player x, Player y) { // String.Compare已處理null情況并支持文化敏感的比較 // StringComparison.Ordinal 表示使用序號(hào)二進(jìn)制比較速度最快 return string.Compare(x?.Name, y?.Name, StringComparison.Ordinal); } } // 使用方式 ListPlayer playersCopy1 new ListPlayer(players); // 創(chuàng)建副本以免影響原列表 playersCopy1.Sort(new LevelAscendingComparer()); Console.WriteLine( 按等級(jí)升序、戰(zhàn)力升序排序 ); foreach (var p in playersCopy1) Console.WriteLine(p); ListPlayer playersCopy2 new ListPlayer(players); playersCopy2.Sort(new NameComparer()); Console.WriteLine(\n 按名字字典序排序 ); foreach (var p in playersCopy2) Console.WriteLine(p);輸出結(jié)果片段 按等級(jí)升序、戰(zhàn)力升序排序 張三 (戰(zhàn)力:8500, 等級(jí):45, 加入:2023-05-10) 王五 (戰(zhàn)力:9200, 等級(jí):48, 加入:2023-04-01) ... 按名字字典序排序 李四 (戰(zhàn)力:9200, 等級(jí):50, 加入:2023-03-15) 孫七 (戰(zhàn)力:9200, 等級(jí):50, 加入:2023-02-28) ...注意事項(xiàng)在IComparer.Compare方法中務(wù)必處理參數(shù)為null的情況這是編寫健壯比較器的關(guān)鍵。上面的代碼給出了一種常見的約定空對(duì)象視為最小排在最前面。對(duì)于字符串比較強(qiáng)烈建議使用string.Compare并指定StringComparison枚舉如Ordinal或CurrentCulture而不是直接使用比較運(yùn)算符,后者可能產(chǎn)生與文化設(shè)定相關(guān)的不確定行為。3.4 方法四使用LINQ的OrderBy與ThenBy聲明式編程最易讀對(duì)于不修改原列表、而是生成新排序序列的場景LINQ是神器。它的語法就像在描述“我想要什么”而不是“我該如何做”。using System.Linq; // 需要引入命名空間 // 使用LINQ進(jìn)行多條件排序 // 規(guī)則戰(zhàn)斗力降序 - 等級(jí)降序 - 注冊(cè)時(shí)間升序 var sortedPlayers players .OrderByDescending(p p.CombatPower) // 第一條件降序 .ThenByDescending(p p.Level) // 第二條件降序 .ThenBy(p p.JoinTime) // 第三條件升序 .ToList(); // 將排序結(jié)果轉(zhuǎn)換為新列表 Console.WriteLine( 使用LINQ排序結(jié)果 ); foreach (var p in sortedPlayers) { Console.WriteLine(p); } // LINQ的強(qiáng)大之處輕松實(shí)現(xiàn)動(dòng)態(tài)排序 string sortBy Level; // 這個(gè)條件可以從配置或用戶輸入讀取 bool isAscending false; IEnumerablePlayer dynamicallySorted; switch (sortBy) { case CombatPower: dynamicallySorted isAscending ? players.OrderBy(p p.CombatPower) : players.OrderByDescending(p p.CombatPower); break; case Level: dynamicallySorted isAscending ? players.OrderBy(p p.Level) : players.OrderByDescending(p p.Level); break; case Name: dynamicallySorted isAscending ? players.OrderBy(p p.Name) : players.OrderByDescending(p p.Name); break; default: dynamicallySorted players; break; }重要區(qū)別與選擇建議List.Sort()是原地排序會(huì)修改原始列表的順序性能通常更高。LINQ OrderBy是生成新序列原始列表順序不變語法更優(yōu)雅易讀且易于組合和延遲執(zhí)行。如何選擇如果排序是最終目的且你不再需要原始順序用List.Sort()。如果你需要保留原始數(shù)據(jù)順序或者排序只是數(shù)據(jù)處理管道中的一環(huán)例如排序后還要過濾、分組用LINQ。在Unity中對(duì)于每幀都需要更新的大型列表如大量敵人的距離排序性能敏感的場合優(yōu)先考慮List.Sort()。對(duì)于UI數(shù)據(jù)綁定、一次性數(shù)據(jù)處理LINQ的代碼可維護(hù)性優(yōu)勢更大。4. 高級(jí)技巧與性能優(yōu)化實(shí)戰(zhàn)掌握了基礎(chǔ)方法后我們來看看在實(shí)際項(xiàng)目中可能遇到的復(fù)雜場景和提升點(diǎn)。4.1 處理復(fù)雜權(quán)重非平等加權(quán)與計(jì)算屬性有時(shí)權(quán)重不是簡單的優(yōu)先級(jí)而是需要計(jì)算一個(gè)綜合得分。例如排行榜分?jǐn)?shù) 戰(zhàn)斗力 * 0.7 等級(jí) * 30 (當(dāng)前時(shí)間 - 注冊(cè)時(shí)間).TotalDays * 0.1鼓勵(lì)老玩家。這時(shí)我們可以在比較器或LINQ的鍵選擇器中直接計(jì)算。// 使用LINQ按綜合得分排序 var rankedPlayers players .OrderByDescending(p p.CombatPower * 0.7f p.Level * 30 (float)(DateTime.Now - p.JoinTime).TotalDays * 0.1f) .ToList(); // 使用IComparer實(shí)現(xiàn)更復(fù)雜的比較邏輯 public class ComprehensiveScoreComparer : IComparerPlayer { private float CalculateScore(Player p) { if (p null) return 0; return p.CombatPower * 0.7f p.Level * 30 (float)(DateTime.Now - p.JoinTime).TotalDays * 0.1f; } public int Compare(Player x, Player y) { float scoreX CalculateScore(x); float scoreY CalculateScore(y); // 降序排列 return scoreY.CompareTo(scoreX); } }注意在IComparer.Compare方法中頻繁計(jì)算得分可能影響性能特別是列表很大時(shí)。一個(gè)優(yōu)化策略是在排序前預(yù)先計(jì)算好每個(gè)對(duì)象的得分并緩存起來。4.2 性能關(guān)鍵點(diǎn)避免在排序中產(chǎn)生GC Alloc在Unity中GC垃圾回收是性能殺手。不當(dāng)?shù)呐判虼a可能引發(fā)不必要的內(nèi)存分配??狱c(diǎn)1Lambda表達(dá)式捕獲外部變量int weightFactor 10; // 一個(gè)外部變量 // 下面的Lambda表達(dá)式會(huì)捕獲weightFactor可能生成一個(gè)閉包類導(dǎo)致GC Alloc players.Sort((x, y) (x.CombatPower * weightFactor).CompareTo(y.CombatPower * weightFactor));優(yōu)化如果weightFactor是常量應(yīng)定義為const。如果是運(yùn)行時(shí)決定的考慮使用獨(dú)立的IComparer類并將參數(shù)通過構(gòu)造函數(shù)傳入??狱c(diǎn)2LINQ生成中間容器// 每次調(diào)用 .ToList() 或 .ToArray() 都會(huì)生成新容器 var sorted players.OrderBy(...).ThenBy(...).ToList(); // 如果players很大且此操作每幀執(zhí)行GC壓力會(huì)很大。優(yōu)化對(duì)于高頻更新的排序考慮使用List.Sort()原地排序。如果必須用LINQ評(píng)估是否可以降低調(diào)用頻率如每10幀一次??狱c(diǎn)3在比較器中創(chuàng)建新對(duì)象public int Compare(Player x, Player y) { // 錯(cuò)誤每次比較都創(chuàng)建新的DateTime和TimeSpanGC災(zāi)難 TimeSpan xActive DateTime.Now - x.LastLoginTime; TimeSpan yActive DateTime.Now - y.LastLoginTime; return xActive.CompareTo(yActive); }優(yōu)化在比較器構(gòu)造函數(shù)中計(jì)算好DateTime.Now或讓Player類提供一個(gè)LastLoginDuration這樣的緩存屬性。4.3 實(shí)現(xiàn)穩(wěn)定排序Stable SortListT.Sort()方法使用的是快速排序算法它是不穩(wěn)定排序。這意味著當(dāng)兩個(gè)元素被比較器判定為“相等”Compare返回0時(shí)它們?cè)谂判蚝蟮南鄬?duì)位置可能是任意的、不可預(yù)測的。這在某些場景下是不可接受的比如你希望先按部門排序再按入職時(shí)間排序并且要求同一部門內(nèi)員工原有的相對(duì)順序如工號(hào)順序保持不變。解決方案使用LINQ的OrderBy和ThenBy。LINQ的排序?qū)崿F(xiàn)是穩(wěn)定的它會(huì)保留原始序列中相等元素的原始順序。如果必須用List.Sort且要求穩(wěn)定一個(gè)技巧是擴(kuò)展比較邏輯在最終比較相等時(shí)比較一個(gè)能保證唯一且反映原始順序的字段比如自增ID或初始索引。// 假設(shè)Player類有一個(gè)唯一ID public class Player { public int Id { get; set; } // 唯一標(biāo)識(shí)通常來自數(shù)據(jù)庫 // ... 其他屬性 ... } // 在比較器的最后加入Id比較以確保穩(wěn)定性和確定性 public int Compare(Player x, Player y) { // ... 主要比較邏輯 ... // 如果所有業(yè)務(wù)字段都相等 return x.Id.CompareTo(y.Id); // 按Id升序保證結(jié)果唯一且穩(wěn)定 }5. 實(shí)戰(zhàn)問題排查與調(diào)試技巧即使理解了原理在實(shí)際編碼中依然會(huì)遇到各種“坑”。下面是一些常見問題及其解決方法。5.1 排序結(jié)果不符合預(yù)期這是最常見的問題。請(qǐng)按以下清單逐步排查檢查升降序邏輯你是否混淆了x.CompareTo(y)和y.CompareTo(x)記住對(duì)于升序用x.CompareTo(y)對(duì)于降序用y.CompareTo(x)。檢查比較器返回值含義你的比較函數(shù)是否遵循了契約返回值必須滿足小于0x應(yīng)排在y之前。等于0x和y順序可視為相等。大于0x應(yīng)排在y之后。驗(yàn)證權(quán)重優(yōu)先級(jí)你的“瀑布式比較”代碼邏輯是否正確是否在每一級(jí)比較后都正確判斷了if (compareResult ! 0) return compareResult;一個(gè)常見的錯(cuò)誤是寫成了多個(gè)獨(dú)立的if語句沒有形成優(yōu)先級(jí)鏈。處理null值你的比較器是否妥善處理了x或y為null的情況未處理的null值會(huì)導(dǎo)致運(yùn)行時(shí)NullReferenceException。通常約定null小于任何非null對(duì)象。調(diào)試你的比較器在比較函數(shù)內(nèi)部添加日志或設(shè)置斷點(diǎn)觀察每一次兩兩比較的輸入和輸出這是最直接的調(diào)試方法。players.Sort((x, y) { int result y.CombatPower.CompareTo(x.CombatPower); Debug.Log($比較 {x?.Name} vs {y?.Name}戰(zhàn)力比較結(jié)果: {result}); if (result ! 0) return result; // ... 其他比較 ... return result; });5.2 自定義類排序時(shí)遇到的編譯或運(yùn)行時(shí)錯(cuò)誤錯(cuò)誤“未能比較數(shù)組中的兩個(gè)元素?!被颉癐Comparer.Compare()方法返回了不一致的結(jié)果。”原因你的比較器違反了“自反性”、“反對(duì)稱性”或“傳遞性”的數(shù)學(xué)契約。例如比較邏輯依賴于隨機(jī)數(shù)、當(dāng)前時(shí)間等可變狀態(tài)或者對(duì)于AB且BC卻得出了AC的矛盾結(jié)論。解決確保比較邏輯基于對(duì)象穩(wěn)定不變的屬性并且邏輯是數(shù)學(xué)上一致的。避免在Compare方法中調(diào)用非純函數(shù)。錯(cuò)誤ListMyClass.Sort()無法編譯提示“必須實(shí)現(xiàn)IComparable接口”原因你調(diào)用了無參數(shù)的Sort()但你的自定義類MyClass沒有實(shí)現(xiàn)IComparableMyClass接口。解決要么讓類實(shí)現(xiàn)IComparable接口要么調(diào)用Sort(ComparisonT)或Sort(IComparerT)重載傳入自定義比較邏輯。5.3 Unity特定場景下的排序應(yīng)用GameObject列表按距離排序這是非常常見的需求例如尋找最近敵人。ListGameObject enemies new ListGameObject(GameObject.FindGameObjectsWithTag(Enemy)); Transform playerTransform GameObject.FindGameObjectWithTag(Player).transform; // 按距離玩家由近到遠(yuǎn)排序 enemies.Sort((a, b) Vector3.Distance(a.transform.position, playerTransform.position) .CompareTo(Vector3.Distance(b.transform.position, playerTransform.position)) ); // 性能提示Distance計(jì)算涉及平方根開銷大。對(duì)于僅比較大小的排序可以使用sqrMagnitude優(yōu)化。 enemies.Sort((a, b) (a.transform.position - playerTransform.position).sqrMagnitude .CompareTo((b.transform.position - playerTransform.position).sqrMagnitude) );UI元素按層級(jí)或優(yōu)先級(jí)排序管理一堆UI彈窗需要按優(yōu)先級(jí)或打開時(shí)間決定顯示順序。public class UIWindow { public int Priority; // 優(yōu)先級(jí)值越小越靠前 public DateTime OpenTime; // ... } ListUIWindow windows GetActiveWindows(); // 先按優(yōu)先級(jí)升序同優(yōu)先級(jí)按打開時(shí)間降序后打開的蓋在先打開的上面 windows.Sort((w1, w2) { int priCompare w1.Priority.CompareTo(w2.Priority); if (priCompare ! 0) return priCompare; return w2.OpenTime.CompareTo(w1.OpenTime); // 注意降序 }); // 排序后列表第一個(gè)元素就是應(yīng)該顯示在最底層的窗口掌握List的排序尤其是多條件權(quán)重排序是Unity C#編程中一項(xiàng)扎實(shí)的基本功。它直接關(guān)系到游戲邏輯的正確性、性能以及代碼的整潔度。從簡單的Lambda表達(dá)式到可復(fù)用的IComparer再到聲明式的LINQ根據(jù)不同的場景選擇最合適的工具能夠讓你的代碼既高效又優(yōu)雅。記住在性能熱點(diǎn)處留意GC問題在復(fù)雜邏輯處確保比較器的正確性和穩(wěn)定性多寫多練這些技巧很快就會(huì)成為你的肌肉記憶。