You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用哈希与字典优化ClientModule列表的查找删除逻辑?

问题

我的程序中,服务器会向客户端发送模块,客户端加载完成后返回模块信息。服务器将待加载的客户端信息存在LoadingClientModules列表里,收到响应后移除对应项标记加载完成。

目前用List.RemoveAll()遍历整个列表,通过匹配ModuleName和TimeDateStamp来移除目标项,不仅效率低,代码可读性也差。想知道能不能通过这两个成员的哈希值改用Dictionary来优化实现。

当前代码:

public List<ClientModule> LoadingClientModules = new();
public List<ClientModule> LoadedClientModules = new();

private void ClientModuleAdded_Callback(Packet packet)
{
    ClientModule f = Utils.ByteArrayToStructure<ClientModule>(packet.Payload, 0);
    Utils.Log.Information($"{_ClientInformation.ComputerUser} Loaded  {f.ModuleName} TimeDateStamp: {f.TimeDateStamp} Address: {f.Address}");
    LoadedClientModules.Add(f);

    LoadingClientModules.RemoveAll(i => i.ModuleName == f.ModuleName && i.TimeDateStamp == f.TimeDateStamp);

    OnClientModuleLoaded?.Invoke(this, f);
}
解决方案

完全可以用Dictionary替代List来优化查找和移除效率,核心是把ModuleName和TimeDateStamp组合成唯一键,直接通过键访问目标项,时间复杂度从O(n)降到O(1)。

有两种常用实现方式:

方式一:用ValueTuple作为Dictionary的键

C# 7.0及以上支持ValueTuple,直接把(string ModuleName, long TimeDateStamp)作为键,无需额外定义类:

// 替换原List为Dictionary,键是ModuleName+TimeDateStamp的组合
public Dictionary<(string ModuleName, long TimeDateStamp), ClientModule> LoadingClientModules = new();
public List<ClientModule> LoadedClientModules = new();

private void ClientModuleAdded_Callback(Packet packet)
{
    ClientModule f = Utils.ByteArrayToStructure<ClientModule>(packet.Payload, 0);
    Utils.Log.Information($"{_ClientInformation.ComputerUser} Loaded  {f.ModuleName} TimeDateStamp: {f.TimeDateStamp} Address: {f.Address}");
    LoadedClientModules.Add(f);

    // 直接通过组合键查找并移除,效率更高
    var key = (f.ModuleName, f.TimeDateStamp);
    LoadingClientModules.Remove(key);

    OnClientModuleLoaded?.Invoke(this, f);
}

注意:添加待加载模块到LoadingClientModules时,也要用同样的组合键作为Key。

方式二:为ClientModule重写GetHashCode和Equals

如果不想用ValueTuple,可以在ClientModule类中重写GetHashCode()和Equals()方法,让类本身可以作为Dictionary的键:

public class ClientModule
{
    public string ModuleName { get; set; }
    public long TimeDateStamp { get; set; }
    public IntPtr Address { get; set; }
    // 其他成员...

    public override bool Equals(object obj)
    {
        if (obj is not ClientModule other)
            return false;
        return ModuleName == other.ModuleName && TimeDateStamp == other.TimeDateStamp;
    }

    public override int GetHashCode()
    {
        // 组合两个字段的哈希值,确保唯一性
        return HashCode.Combine(ModuleName, TimeDateStamp);
    }
}

然后Dictionary定义为:

public Dictionary<ClientModule, ClientModule> LoadingClientModules = new();
// 或者如果不需要存重复对象,也可以用HashSet<ClientModule>,更轻量
// public HashSet<ClientModule> LoadingClientModules = new();

回调方法中移除逻辑改为:

LoadingClientModules.Remove(f);
// 如果用HashSet就是 LoadingClientModules.Remove(f);

注意事项

  • 确保ModuleName和TimeDateStamp的组合是唯一的,避免键冲突导致数据丢失。
  • 如果用ValueTuple作为键,要保证两个字段的类型和顺序完全匹配。
  • 若ClientModule是可变类,要避免作为键的字段(ModuleName、TimeDateStamp)在存入Dictionary后被修改,否则会导致无法正确查找。

内容的提问来源于stack exchange,提问作者Meme Machine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:54:18