C#獲取不重復(fù)的編碼的最佳實(shí)踐
一、需求背景:為什么需要“不重復(fù)編碼”?
在業(yè)務(wù)開發(fā)中,“編碼唯一性”是保障數(shù)據(jù)準(zhǔn)確性的基礎(chǔ)要求。以通信設(shè)備管理系統(tǒng)為例:
- 系統(tǒng)維護(hù)一個(gè)通信模塊集合
ComList(存儲(chǔ)ICommunication類型對(duì)象) - 每個(gè)新接入的通信模塊(
ec)需分配唯一Encode值 - 若
Encode重復(fù),會(huì)導(dǎo)致設(shè)備標(biāo)識(shí)混亂,引發(fā)查詢錯(cuò)誤、指令發(fā)送失敗等問題
因此,在將新模塊添加到集合前,必須先找到一個(gè)“未被使用的編碼”,這是確保系統(tǒng)穩(wěn)定運(yùn)行的關(guān)鍵步驟。
二、原始實(shí)現(xiàn):邏輯可行但不夠優(yōu)雅
先看一段常見的原始代碼,核心思路是“從0開始逐個(gè)檢查,直到找到未使用的編碼”:
// 原始代碼:獲取不重復(fù)編碼
bool flag = false;
int encode = 0;
do
{
flag = true; // 假設(shè)當(dāng)前編碼可用
// 遍歷集合檢查編碼是否已存在
foreach (ICommunication tempEC in ComList)
{
if (tempEC.Encode == encode)
{
encode++; // 編碼已使用,自增后重新檢查
flag = false;
break; // 跳出foreach,進(jìn)入下一輪do-while
}
}
// 若編碼可用,跳出循環(huán)
if (flag == true)
{
break;
}
} while (true);
// 為新模塊賦值并添加到集合
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);
原始代碼的問題
- 冗余標(biāo)記變量:用
flag控制循環(huán)退出,增加理解成本(實(shí)際可通過循環(huán)條件直接表達(dá)) - 嵌套層次深:
do-while嵌套foreach,再嵌套if,代碼結(jié)構(gòu)復(fù)雜 - 重復(fù)遍歷:每次檢查都需手動(dòng)遍歷集合,未利用現(xiàn)有工具簡(jiǎn)化邏輯
三、第一次優(yōu)化:用LINQ簡(jiǎn)化邏輯
C#的LINQ(Language Integrated Query) 提供了豐富的集合操作方法,其中Any()方法可直接判斷“集合是否存在滿足條件的元素”,能大幅簡(jiǎn)化代碼。
1. 優(yōu)化后代碼
// 優(yōu)化方案1:基于LINQ的簡(jiǎn)潔實(shí)現(xiàn)
int encode = 0;
// 循環(huán)條件:若集合中存在該編碼,則繼續(xù)自增檢查
while (ComList.Any(ec => ec.Encode == encode))
{
encode++;
}
// 后續(xù)賦值與添加邏輯不變
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);
2. 核心邏輯解析:ComList.Any(ec => ec.Encode == encode)
這行代碼是優(yōu)化的核心,拆解理解:
ComList:待檢查的通信模塊集合(存儲(chǔ)ICommunication對(duì)象)Any()方法:LINQ擴(kuò)展方法,作用是“判斷集合是否至少存在一個(gè)滿足條件的元素”- 返回值:
bool(存在則true,不存在則false) - 優(yōu)勢(shì):短路求值——找到第一個(gè)滿足條件的元素后,立即停止遍歷,避免無效循環(huán)
- 返回值:
ec => ec.Encode == encode:lambda表達(dá)式(匿名函數(shù)),定義判斷規(guī)則ec:集合中元素的臨時(shí)變量(可理解為“each communication”,建議取有意義的名稱)ec.Encode:獲取當(dāng)前模塊的編碼屬性== encode:判斷當(dāng)前編碼是否與待分配的encode重復(fù)
通俗解釋:檢查ComList中是否有任何一個(gè)模塊的Encode等于當(dāng)前encode值。若有(返回true),則encode自增繼續(xù)檢查;若無(返回false),則找到可用編碼,循環(huán)結(jié)束。
3. 優(yōu)化點(diǎn)總結(jié)
- 去除
flag變量,用while條件直接控制退出,邏輯更直觀 - 消除嵌套層次,代碼從“嵌套結(jié)構(gòu)”變?yōu)?ldquo;線性結(jié)構(gòu)”,可讀性提升
- 代碼量減少60%+,同時(shí)保持功能完全一致
四、第二次優(yōu)化:大數(shù)據(jù)量場(chǎng)景的性能提升
方案1在中小數(shù)據(jù)量(如ComList元素<1000)場(chǎng)景下足夠高效,但當(dāng)集合元素極多(如萬級(jí)以上)或需頻繁分配編碼時(shí),每次調(diào)用ComList.Any()都需遍歷集合,性能會(huì)下降。
此時(shí)可通過哈希集合(HashSet) 優(yōu)化——哈希集合的Contains方法時(shí)間復(fù)雜度為O(1),遠(yuǎn)快于普通集合的O(n)。
1. 優(yōu)化思路
- 預(yù)提取
ComList中所有已使用的Encode,存入HashSet<int> - 基于哈希集合的
Contains方法檢查編碼是否重復(fù),大幅減少查找時(shí)間
2. 優(yōu)化后代碼
// 優(yōu)化方案2:大數(shù)據(jù)量場(chǎng)景下的高性能實(shí)現(xiàn)
// 步驟1:預(yù)提取已使用的編碼到哈希集合
var existingEncodes = new HashSet<int>(ComList.Select(ec => ec.Encode));
// 步驟2:檢查可用編碼
int encode = 0;
while (existingEncodes.Contains(encode))
{
encode++;
}
// 后續(xù)賦值與添加邏輯不變
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);
3. 關(guān)鍵代碼解析
ComList.Select(ec => ec.Encode):LINQ的Select方法“投影”集合元素,將ICommunication對(duì)象轉(zhuǎn)換為其Encode屬性(得到IEnumerable<int>序列)new HashSet<int>(...):通過序列初始化哈希集合,存儲(chǔ)所有已使用的編碼existingEncodes.Contains(encode):哈希集合的快速查找方法,無論集合大小,均能瞬間判斷編碼是否存在
4. 適用場(chǎng)景
ComList元素?cái)?shù)量多(如>1000)- 短時(shí)間內(nèi)頻繁添加新模塊(需多次獲取不重復(fù)編碼)
注意:若數(shù)據(jù)量小,方案2的“哈希集合初始化開銷”可能大于遍歷節(jié)省的時(shí)間,反而得不償失,此時(shí)方案1更優(yōu)。
五、總結(jié):不同場(chǎng)景的方案選擇
| 場(chǎng)景 | 推薦方案 | 核心優(yōu)勢(shì) | 時(shí)間復(fù)雜度 |
|---|---|---|---|
| 中小數(shù)據(jù)量(<1000) | LINQ Any() | 代碼簡(jiǎn)潔、無額外開銷 | O(n) |
| 大數(shù)據(jù)量/頻繁操作 | 哈希集合 | 查找速度極快 | O(1) |
| 原始實(shí)現(xiàn) | 不推薦 | 邏輯冗余、可讀性差 | O(n²) |
最終推薦代碼(通用場(chǎng)景)
若不確定數(shù)據(jù)量,可優(yōu)先使用方案1(LINQ實(shí)現(xiàn)),代碼簡(jiǎn)潔且滿足多數(shù)業(yè)務(wù)需求:
// 完整通用實(shí)現(xiàn)代碼
using System;
using System.Collections.Generic;
using System.Linq; // 需引用LINQ命名空間
// 假設(shè)的通信模塊接口
public interface ICommunication
{
int Encode { get; set; }
string Key { get; set; }
}
// 通信模塊實(shí)現(xiàn)類
public class CommunicationModule : ICommunication
{
public int Encode { get; set; }
public string Key { get; set; }
}
public class CommunicationManager
{
// 通信模塊集合
private List<ICommunication> ComList = new List<ICommunication>();
// 添加新通信模塊(核心方法)
public void AddNewModule(string keyPrefix)
{
// 1. 獲取不重復(fù)編碼
int encode = 0;
while (ComList.Any(ec => ec.Encode == encode))
{
encode++;
}
// 2. 為新模塊賦值
ICommunication ec = new CommunicationModule();
string key = keyPrefix + encode;
ec.Key = key;
ec.Encode = encode;
// 3. 添加到集合
ComList.Add(ec);
Console.WriteLine($"新模塊添加成功:Key={key},Encode={encode}");
}
}
六、拓展思考
- 編碼起始值:若需從非0值(如100)開始分配編碼,只需將
int encode = 0改為int encode = 100即可 - 編碼步長(zhǎng):若需按固定步長(zhǎng)(如2)分配編碼,可將
encode++改為encode += 2 - 并發(fā)安全:若多線程同時(shí)添加模塊,需在編碼檢查和添加集合時(shí)加鎖(如
lock(ComList)),避免并發(fā)沖突
到此這篇關(guān)于C#獲取不重復(fù)的編碼的最佳實(shí)踐的文章就介紹到這了,更多相關(guān)C#獲取不重復(fù)編碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#數(shù)據(jù)結(jié)構(gòu)之單鏈表(LinkList)實(shí)例詳解
這篇文章主要介紹了C#數(shù)據(jù)結(jié)構(gòu)之單鏈表(LinkList)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了單鏈表的原理、定義與C#具體實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
C#創(chuàng)建簡(jiǎn)單windows窗體應(yīng)用(加法器)
這篇文章主要為大家詳細(xì)介紹了C#創(chuàng)建一個(gè)簡(jiǎn)單windows窗體應(yīng)用的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
C#使用Stopwatch實(shí)現(xiàn)計(jì)時(shí)功能
在 C# 中,Stopwatch 類是用于測(cè)量經(jīng)過的時(shí)間的工具類,提供了高精度的計(jì)時(shí)功能,本文主要介紹了C#如何使用Stopwatch實(shí)現(xiàn)計(jì)時(shí)功能,需要的可以參考下2024-03-03
C#網(wǎng)絡(luò)爬蟲代碼分享 C#簡(jiǎn)單的爬取工具
這篇文章主要為大家詳細(xì)介紹了C#網(wǎng)絡(luò)爬蟲代碼,教大家如何制作了簡(jiǎn)單的爬取工具,感興趣的小伙伴們可以參考一下2016-07-07
ItemsControl 數(shù)據(jù)綁定的兩種方式
這篇文章主要介紹了ItemsControl 數(shù)據(jù)綁定的兩種方式,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03

