C#获取不重复的编码的最佳实践

 更新时间:2025年09月22日 09:10:26   作者:code bean  
本文针对软件开发中“为新对象分配唯一编码”的常见需求,以C#通信设备管理场景为例,从原始代码分析入手,逐步讲解基于LINQ和哈希集合的优化方案,帮助开发者理解不同场景下的最佳实践,需要的朋友可以参考下

一、需求背景:为什么需要“不重复编码”?

在业务开发中,“编码唯一性”是保障数据准确性的基础要求。以通信设备管理系统为例:

  • 系统维护一个通信模块集合ComList(存储ICommunication类型对象)
  • 每个新接入的通信模块(ec)需分配唯一Encode
  • Encode重复,会导致设备标识混乱,引发查询错误、指令发送失败等问题

因此,在将新模块添加到集合前,必须先找到一个“未被使用的编码”,这是确保系统稳定运行的关键步骤。

二、原始实现:逻辑可行但不够优雅

先看一段常见的原始代码,核心思路是“从0开始逐个检查,直到找到未使用的编码”:

// 原始代码:获取不重复编码
bool flag = false;
int encode = 0;
do
{
    flag = true; // 假设当前编码可用
    // 遍历集合检查编码是否已存在
    foreach (ICommunication tempEC in ComList)
    {
        if (tempEC.Encode == encode)
        {
            encode++; // 编码已使用,自增后重新检查
            flag = false;
            break; // 跳出foreach,进入下一轮do-while
        }
    }
    // 若编码可用,跳出循环
    if (flag == true)
    {
        break;
    }
} while (true);

// 为新模块赋值并添加到集合
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);

原始代码的问题

  1. 冗余标记变量:用flag控制循环退出,增加理解成本(实际可通过循环条件直接表达)
  2. 嵌套层次深do-while嵌套foreach,再嵌套if,代码结构复杂
  3. 重复遍历:每次检查都需手动遍历集合,未利用现有工具简化逻辑

三、第一次优化:用LINQ简化逻辑

C#的LINQ(Language Integrated Query) 提供了丰富的集合操作方法,其中Any()方法可直接判断“集合是否存在满足条件的元素”,能大幅简化代码。

1. 优化后代码

// 优化方案1:基于LINQ的简洁实现
int encode = 0;
// 循环条件:若集合中存在该编码,则继续自增检查
while (ComList.Any(ec => ec.Encode == encode))
{
    encode++;
}

// 后续赋值与添加逻辑不变
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);

2. 核心逻辑解析:ComList.Any(ec => ec.Encode == encode)

这行代码是优化的核心,拆解理解:

  • ComList:待检查的通信模块集合(存储ICommunication对象)
  • Any()方法:LINQ扩展方法,作用是“判断集合是否至少存在一个满足条件的元素”
    • 返回值:bool(存在则true,不存在则false
    • 优势:短路求值——找到第一个满足条件的元素后,立即停止遍历,避免无效循环
  • ec => ec.Encode == encode:lambda表达式(匿名函数),定义判断规则
    • ec:集合中元素的临时变量(可理解为“each communication”,建议取有意义的名称)
    • ec.Encode:获取当前模块的编码属性
    • == encode:判断当前编码是否与待分配的encode重复

通俗解释:检查ComList中是否有任何一个模块的Encode等于当前encode值。若有(返回true),则encode自增继续检查;若无(返回false),则找到可用编码,循环结束。

3. 优化点总结

  • 去除flag变量,用while条件直接控制退出,逻辑更直观
  • 消除嵌套层次,代码从“嵌套结构”变为“线性结构”,可读性提升
  • 代码量减少60%+,同时保持功能完全一致

四、第二次优化:大数据量场景的性能提升

方案1在中小数据量(如ComList元素<1000)场景下足够高效,但当集合元素极多(如万级以上)或需频繁分配编码时,每次调用ComList.Any()都需遍历集合,性能会下降。

此时可通过哈希集合(HashSet) 优化——哈希集合的Contains方法时间复杂度为O(1),远快于普通集合的O(n)

1. 优化思路

  1. 预提取ComList中所有已使用的Encode,存入HashSet<int>
  2. 基于哈希集合的Contains方法检查编码是否重复,大幅减少查找时间

2. 优化后代码

// 优化方案2:大数据量场景下的高性能实现
// 步骤1:预提取已使用的编码到哈希集合
var existingEncodes = new HashSet<int>(ComList.Select(ec => ec.Encode));

// 步骤2:检查可用编码
int encode = 0;
while (existingEncodes.Contains(encode))
{
    encode++;
}

// 后续赋值与添加逻辑不变
key = key + encode;
ec.Key = key;
ec.Encode = encode;
ComList.Add(ec);

3. 关键代码解析

  • ComList.Select(ec => ec.Encode):LINQ的Select方法“投影”集合元素,将ICommunication对象转换为其Encode属性(得到IEnumerable<int>序列)
  • new HashSet<int>(...):通过序列初始化哈希集合,存储所有已使用的编码
  • existingEncodes.Contains(encode):哈希集合的快速查找方法,无论集合大小,均能瞬间判断编码是否存在

4. 适用场景

  • ComList元素数量多(如>1000)
  • 短时间内频繁添加新模块(需多次获取不重复编码)

注意:若数据量小,方案2的“哈希集合初始化开销”可能大于遍历节省的时间,反而得不偿失,此时方案1更优。

五、总结:不同场景的方案选择

场景推荐方案核心优势时间复杂度
中小数据量(<1000)LINQ Any()代码简洁、无额外开销O(n)
大数据量/频繁操作哈希集合查找速度极快O(1)
原始实现不推荐逻辑冗余、可读性差O(n²)

最终推荐代码(通用场景)

若不确定数据量,可优先使用方案1(LINQ实现),代码简洁且满足多数业务需求:

// 完整通用实现代码
using System;
using System.Collections.Generic;
using System.Linq; // 需引用LINQ命名空间

// 假设的通信模块接口
public interface ICommunication
{
    int Encode { get; set; }
    string Key { get; set; }
}

// 通信模块实现类
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. 获取不重复编码
        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}");
    }
}

六、拓展思考

  1. 编码起始值:若需从非0值(如100)开始分配编码,只需将int encode = 0改为int encode = 100即可
  2. 编码步长:若需按固定步长(如2)分配编码,可将encode++改为encode += 2
  3. 并发安全:若多线程同时添加模块,需在编码检查和添加集合时加锁(如lock(ComList)),避免并发冲突

到此这篇关于C#获取不重复的编码的最佳实践的文章就介绍到这了,更多相关C#获取不重复编码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#数据结构之单链表(LinkList)实例详解

    C#数据结构之单链表(LinkList)实例详解

    这篇文章主要介绍了C#数据结构之单链表(LinkList)实现方法,结合实例形式较为详细的分析了单链表的原理、定义与C#具体实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • C#创建简单windows窗体应用(加法器)

    C#创建简单windows窗体应用(加法器)

    这篇文章主要为大家详细介绍了C#创建一个简单windows窗体应用的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • C#使用Stopwatch实现计时功能

    C#使用Stopwatch实现计时功能

    在 C# 中,Stopwatch 类是用于测量经过的时间的工具类,提供了高精度的计时功能,本文主要介绍了C#如何使用Stopwatch实现计时功能,需要的可以参考下
    2024-03-03
  • 为何Linq的Distinct实在是不给力

    为何Linq的Distinct实在是不给力

    本篇文章对Linq的Distinct进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C#中Json的简单处理方法

    C#中Json的简单处理方法

    这篇文章主要介绍了C#中Json的简单处理方法的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • C#网络爬虫代码分享 C#简单的爬取工具

    C#网络爬虫代码分享 C#简单的爬取工具

    这篇文章主要为大家详细介绍了C#网络爬虫代码,教大家如何制作了简单的爬取工具,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Unity实现换装系统

    Unity实现换装系统

    这篇文章主要为大家详细介绍了Unity实现换装系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • ItemsControl 数据绑定的两种方式

    ItemsControl 数据绑定的两种方式

    这篇文章主要介绍了ItemsControl 数据绑定的两种方式,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • C#生成随机数实例

    C#生成随机数实例

    这篇文章主要介绍了C#生成随机数的方法,实例分析了随机数的生成原理与使用技巧,需要的朋友可以参考下
    2015-01-01
  • WPF实现自定义窗体的示例代码

    WPF实现自定义窗体的示例代码

    .Net默认的窗体样式只有四种,而且都比较“丑”,但是很多时候,我们希望自定义窗体,比如,无边框,有阴影等,所以本文为大家介绍了WPF实现自定义窗体的方法,希望对大家有所帮助
    2023-09-09

最新评论