优化Discord/Revolt/IRC桥接服务嵌套配置遍历方案咨询
优化跨平台聊天桥接服务的配置解析逻辑
我正在构建一个跨Discord、Revolt及两个独立IRC网络的专用桥接服务,目标是实现匿名性且方便其他用户配置。在处理桥接通道配置时,Discord和Revolt的配置很简单,但IRC网络的配置比较特殊——不同IRC网络的配置没有固定键名,而是用提前定义的网络名称作为键。
配置格式与实体类
设计的TOML配置如下:
[[bridge]] [bridge.chat] discord = "<discord-channel-id>" revolt = "<revolt-channel-id>" libera = "#<channel-name>" oftc = "#<channel-name>"
所有配置键均为非必填项,libera、oftc这类键可替换为任意提前定义的IRC网络名称。
对应的C#实体类:
public class bridges { string bridgeName = ""; Dictionary<string, string> ircChannels = new Dictionary<string, string>(); string revoltChannel = ""; ulong discordChannel = 0; bool hasIrcConnection = false; // 省略getter/setter }
当前问题
目前采用嵌套遍历解析配置,在switch-case处理完Discord/Revolt后,还要嵌套foreach遍历IRC网络列表匹配键,效率较低:
case "bridge": foreach(TomlTable table in tArr) { foreach(string tableKey in table.Keys) { bridges bridge = new bridges(); bridge.BridgeName = tableKey; foreach(var item in (TomlTable)table[bridge.BridgeName]) { switch (item.Key) { case "discord": bridge.DiscordChannel = (ulong)item.Value; break; case "revolt": bridge.RevoltChannel = (string)item.Value; break; } foreach (string server in ircCommunityNames) // ircCommunityNames为提前初始化的IRC网络名称列表,示例:["libera", "oftc"] { if(server == item.Key) { bridge.IrcChannels.Add(server, (string)item.Value); } } } if(bridge.IrcChannels.Count > 0) { bridge.HasIrcConnection = true; } bridgeConfigs.Add(bridge); } } break;
希望避免这种嵌套多重遍历的低效逻辑,求更优实现方案。
优化方案
1. 用HashSet替代List,消除内层遍历
将ircCommunityNames从List<string>转为HashSet<string>,这样判断键是否属于IRC网络的时间复杂度从O(n)降至O(1),直接去掉内层foreach循环。
2. 合并逻辑,单次遍历完成所有处理
遍历每个配置项时,先处理Discord/Revolt的固定键,再用HashSet快速判断当前键是否为IRC网络名称,一次遍历完成所有赋值:
优化后的代码:
// 提前初始化HashSet,替换原List<string> ircCommunityNames HashSet<string> ircServerSet = new HashSet<string>(ircCommunityNames); case "bridge": foreach(TomlTable table in tArr) { foreach(string tableKey in table.Keys) { bridges bridge = new bridges(); bridge.BridgeName = tableKey; var chatTable = (TomlTable)table[tableKey]; foreach(var item in chatTable) { var key = item.Key; var value = item.Value; // 处理固定平台配置,处理完直接跳过后续判断 switch (key) { case "discord": bridge.DiscordChannel = (ulong)value; continue; case "revolt": bridge.RevoltChannel = (string)value; continue; } // 快速判断并添加IRC通道配置 if(ircServerSet.Contains(key)) { bridge.IrcChannels.Add(key, (string)value); } } bridge.HasIrcConnection = bridge.IrcChannels.Count > 0; bridgeConfigs.Add(bridge); } } break;
3. 进阶优化:利用TOML序列化库自动映射
如果使用TOML序列化库(如Tomlyn、Nett),可以通过自定义映射规则省去手动遍历代码:
- 实体类中保留Discord/Revolt的固定属性,用
Dictionary<string, string>接收未匹配的键值对 - 后续仅需过滤字典中属于
ircCommunityNames的项即可
示例(以Tomlyn为例):
public class BridgeConfig { [TomlProperty("discord")] public ulong DiscordChannel { get; set; } [TomlProperty("revolt")] public string RevoltChannel { get; set; } public Dictionary<string, string> IrcChannels { get; set; } = new(); // 捕获所有未匹配的键值对 [TomlIgnore] private Dictionary<string, object>? _extraProperties; [TomlConstructor] public BridgeConfig(TomlTable table) { // 自动填充固定属性 Tomlyn.Model.TomlModelSerializer.Default.Deserialize(table, this); // 过滤IRC网络配置 if(_extraProperties != null) { foreach(var kvp in _extraProperties) { if(ircServerSet.Contains(kvp.Key) && kvp.Value is string channel) { IrcChannels.Add(kvp.Key, channel); } } } } }
这种方式代码更简洁,维护成本更低,适合长期迭代。
内容的提问来源于stack exchange,提问作者Northern Scrub
相关产品推荐
相关产品推荐

