C#常用类库-详解Ecng.Collections

C#常用类库-详解Ecng.Collections

在C#开发中,System.Collections.Generic 提供了基础的集合类型(List<T>Dictionary<TKey, TValue>),但在高性能场景、并发操作、特殊数据结构(如双向链表、循环缓冲区)及内存优化方面,原生集合往往存在不足。

Ecng.Collections 作为一款专注于 高性能、线程安全、特殊数据结构 的扩展类库,由Ecng团队开发,它完美补充了 .NET 原生集合的短板,提供了如 ObservableList<T>ConcurrentHashSet<T>CyclicBuffer<T> 等高频实用组件,是游戏服务器、高频交易系统、并发中间件及高性能后端开发的"隐形神器"。

本文聚焦"简练、详细、有深度",从核心价值、环境搭建、核心数据结构、进阶技巧到实战落地,全方位解析 Ecng.Collections,帮你将集合操作效率提升一个档次,解决原生集合无法覆盖的高频场景痛点。

一、核心定位:Ecng.Collections 解决什么问题?

Ecng.Collections 的核心不是"替代"原生集合,而是 "扩展""优化"。它针对原生集合的痛点,提供了三大核心解决方案,精准匹配高性能、高并发场景需求:

  • 缺失的关键结构 :原生库缺少 HashSet 的线程安全版本、强类型的双向链表、循环缓冲区等,Ecng.Collections 直接补齐,无需手动封装。

  • 高性能优化:针对频繁增删、查找的场景,采用内存优化布局(减少装箱、优化指针操作),核心操作速度优于原生集合,尤其适合高频读写场景。

  • 线程安全与可观测性 :原生 ConcurrentDictionary 功能有限,Ecng.Collections 提供更精细的并发集合;同时内置 INotifyCollectionChanged 支持,完美适配 MVVM 数据绑定,无需额外封装。

核心优势对比(原生 vs Ecng)

特性 System.Collections.Generic Ecng.Collections
线程安全集合 有限(仅 ConcurrentDictionary/ConcurrentQueue) 丰富(ConcurrentHashSet、ConcurrentObservableStack 等)
特殊数据结构 较少(仅基础链表、队列) 齐全(双向链表、循环缓冲区、树节点、优先队列)
数据绑定支持 需手动实现(ObservableCollection 性能一般) 原生支持(ObservableList、ObservableDictionary)
性能 通用场景良好,高频操作有瓶颈 极高(针对高频增删查优化,内存开销低)
API 友好度 基础够用,扩展能力弱 更简洁(提供通用扩展方法,简化代码)

二、环境搭建:快速引入与初始化

Ecng.Collections 是纯 NuGet 包,无任何第三方依赖,安装简单,开箱即用,适配所有 .NET Standard 2.0+ 项目(.NET Core 2.0+、.NET 5+ 均支持)。

1. 安装 NuGet 包

打开 NuGet 包管理器,搜索"Ecng.Collections"安装,或执行以下 .NET CLI 命令:

bash 复制代码
// 核心包(必装,包含所有核心集合结构与扩展方法)
dotnet add package Ecng.Collections

// 可选扩展包(包含与其他 Ecng 生态的集成,如日志、序列化)
// dotnet add package Ecng.Collections.Extensions

2. 核心命名空间

使用前只需引入两个核心命名空间,即可调用所有集合与扩展方法:

csharp 复制代码
using Ecng.Collections; // 核心集合类(ConcurrentHashSet、ObservableList 等)
using Ecng.Common;     // 通用扩展方法(集合转换、安全操作等)

三、核心数据结构详解(必学篇)

Ecng.Collections 提供了数十种集合,但企业级开发中最常用、最核心的是以下 5 类,掌握它们能覆盖 90% 的高频场景,重点关注"适用场景+核心API+性能优势"。

1. 线程安全哈希集 (ConcurrentHashSet) ------ 并发去重首选

原生痛点 :.NET 原生没有线程安全的 HashSet<T>,若要实现并发去重,需手动加锁(lock),不仅代码繁琐,还会影响性能。

核心价值:高性能的并发去重集合,所有操作(Add、Remove、Contains)均为原子性,无需外部锁,支持批量操作,适合多线程去重场景(如用户ID去重、请求去重)。

csharp 复制代码
// 1. 创建并发HashSet(支持自定义比较器,默认使用EqualityComparer<T>.Default)
var set = new ConcurrentHashSet<int>();

// 2. 原子添加(返回是否成功添加,重复添加返回false)
bool added = set.Add(1);       // true
bool alreadyExists = set.Add(1); // false

// 3. 原子移除(返回是否成功移除)
bool removed = set.Remove(1);  // true

// 4. 快速查找(O(1)时间复杂度,线程安全)
bool exists = set.Contains(1); // false

// 5. 批量操作(原子性,避免多次锁竞争)
set.AddRange(new[] { 2, 3, 4 });  // 批量添加
set.RemoveRange(new[] { 2, 3 });  // 批量移除

// 6. 线程安全枚举(避免枚举时修改集合导致的InvalidOperationException)
foreach (var item in set.SafeEnumerable()) 
{
    Console.WriteLine(item); // 输出 4
}

// 7. 手动锁控制(适合复杂批量操作)
using (set.Lock()) // 获取读写锁,using结束自动释放
{
    foreach (var item in set)
    {
        if (item % 2 == 0) set.Remove(item);
    }
}

2. 可观测列表 (ObservableList) ------ MVVM 绑定神器

原生痛点ObservableCollection<T> 在频繁修改(如批量添加、删除)时,会多次触发 CollectionChanged 事件,导致 UI 频繁刷新,性能不佳;且缺少批量操作 API。

核心价值 :高性能可观测集合,实现 INotifyCollectionChangedINotifyPropertyChanged,支持批量更新(仅触发一次事件),精准控制事件触发,完美适配 WPF、Blazor 等 MVVM 场景。

csharp 复制代码
// 1. 创建可观测列表
var list = new ObservableList<string>();

// 2. 订阅集合变化事件(UI绑定自动响应)
list.CollectionChanged += (s, e) =>
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            Console.WriteLine($"添加元素:{e.NewItems[0]}");
            break;
        case NotifyCollectionChangedAction.Remove:
            Console.WriteLine($"移除元素:{e.OldItems[0]}");
            break;
        case NotifyCollectionChangedAction.Reset:
            Console.WriteLine("集合已重置");
            break;
    }
};

// 3. 基础操作(与List<T> API 完全兼容,学习成本低)
list.Add("Apple");
list.Insert(0, "Banana"); // 插入到头部
list.RemoveAt(0);        // 移除头部元素

// 4. 核心优势:批量操作(仅触发一次CollectionChanged事件)
// 避免多次修改导致UI频繁刷新,大幅提升性能
list.AddRange(new[] { "Orange", "Grape", "Mango" }); 
list.RemoveRange(new[] { "Apple" });

// 5. 精准控制事件(暂停/恢复通知,适合大量修改场景)
list.SuspendNotifications(); // 暂停事件通知
list.Clear();                 // 不触发事件
list.AddRange(new[] { "Pear", "Peach" }); // 不触发事件
list.ResumeNotifications();   // 恢复通知,触发一次Reset事件

3. 循环缓冲区 (CyclicBuffer) ------ 固定大小缓存首选

原生痛点:实现"固定大小、先进先出(FIFO)、满了自动覆盖最旧元素"的缓存逻辑,需手动封装数组+索引,代码繁琐且易出错。

核心价值:经典 FIFO 循环结构,内存占用固定,无需手动管理扩容/收缩,适合日志记录、消息缓存、滑动窗口计算等场景(如保留最近1000条日志)。

csharp 复制代码
// 1. 创建容量为3的循环缓冲区(固定容量,不可修改)
var buffer = new CyclicBuffer<int>(3);

// 2. 添加元素(满了自动覆盖最旧元素)
buffer.Push(1); // 缓冲区:[1]
buffer.Push(2); // 缓冲区:[1, 2]
buffer.Push(3); // 缓冲区:[1, 2, 3](已满)
buffer.Push(4); // 覆盖最旧的1,缓冲区:[2, 3, 4]

// 3. 弹出元素(获取并移除最旧元素,FIFO)
int oldest = buffer.Pop(); // 返回2,缓冲区变为 [3, 4]

// 4. 查看元素(不移除)
int peekOldest = buffer.Peek();    // 查看最旧元素:3
int peekLatest = buffer.PeekLast();// 查看最新元素:4

// 5. 安全操作与状态判断
bool hasValue = buffer.TryPop(out int value); // 安全弹出,返回是否成功
int count = buffer.Count;         // 当前元素数量:2
bool isFull = buffer.IsFull;      // 是否已满:false(容量3,当前2个)
bool isEmpty = buffer.IsEmpty;    // 是否为空:false

// 6. 批量填充与清空
buffer.Fill(new[] { 5, 6, 7 });   // 填充后:[5, 6, 7](已满)
buffer.Clear();                   // 清空缓冲区

4. 双向链表 (LinkedList2) ------ 中间增删高效

原生痛点 :原生 LinkedList<T> 节点结构封闭,操作繁琐(如中间插入需先查找节点),且缺少反向遍历、批量操作等高频 API。

核心价值 :更易用、更高效的双向链表实现,提供简洁的 AddAfterAddBeforeFind 等 API,支持正向/反向遍历,适合频繁在列表中间增删的场景(如任务队列、消息链表)。

csharp 复制代码
// 1. 创建双向链表
var ll = new LinkedList2<int>();

// 2. 添加元素(返回节点引用,便于后续中间插入)
var node1 = ll.AddFirst(1); // 添加到头部,返回节点
var node3 = ll.AddLast(3);  // 添加到尾部,返回节点

// 3. 中间插入(高效,无需遍历整个链表)
ll.AddAfter(node1, 2); // 在1后面插入2,链表:1 <-> 2 <-> 3

// 4. 遍历(正向/反向,API简洁)
foreach (var item in ll) Console.Write($"{item} "); // 1 2 3
foreach (var item in ll.Reverse()) Console.Write($"{item} "); // 3 2 1

// 5. 查找与移除(高效)
var node2 = ll.Find(2); // 查找值为2的节点(O(n),但节点操作O(1))
ll.Remove(node2);       // 移除指定节点,链表变为:1 <-> 3

// 6. 批量操作
ll.AddRange(new[] { 4, 5 }); // 批量添加到尾部
ll.RemoveRange(new[] { 1, 3 }); // 批量移除

5. 并发可观测字典 (ConcurrentObservableDictionary<TKey, TValue>) ------ 并发+绑定双需求

原生痛点 :原生 ConcurrentDictionary 不支持 INotifyCollectionChanged,无法直接用于 MVVM 绑定;而 ObservableDictionary 是非线程安全的,多线程环境下易报错。

核心价值 :线程安全与可观测性的完美结合,既支持原子性的字典操作,又能触发 CollectionChanged 事件,适用于多线程环境下的 UI 数据绑定(如实时更新的配置字典)。

csharp 复制代码
// 1. 创建并发可观测字典
var dict = new ConcurrentObservableDictionary<int, string>();

// 2. 订阅集合变化事件(UI自动响应)
dict.CollectionChanged += (s, e) =>
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        var kvp = (KeyValuePair<int, string>)e.NewItems[0];
        Console.WriteLine($"添加键值对:{kvp.Key}={kvp.Value}");
    }
};

// 3. 线程安全操作(所有操作均为原子性,同时触发事件)
dict.TryAdd(1, "One");       // 安全添加,触发Add事件
dict[2] = "Two";             // 索引器操作,线程安全
dict.TryUpdate(2, "Two_New", "Two"); // 原子更新(匹配旧值才更新)
dict.TryRemove(1, out _);    // 安全移除

// 4. 多线程并发测试(模拟100个线程同时添加)
Parallel.For(0, 100, i =>
{
    dict.TryAdd(i, $"Value_{i}");
});

// 5. 绑定UI(WPF示例)
// <DataGrid ItemsSource="{Binding Dict}" />
// ViewModel 中直接暴露 Dict 属性即可

四、进阶技巧:实战必备(深度重点)

掌握基础数据结构后,以下进阶技巧能进一步提升开发效率,规避性能问题,适配更复杂的企业级场景。

1. 集合转换与互操作(原生 ↔ Ecng)

Ecng.Collections 提供了丰富的扩展方法,可快速在原生集合与 Ecng 集合之间转换,无需手动遍历赋值,简化代码。

csharp 复制代码
// 1. 原生List<T> → Ecng ObservableList<T>
var nativeList = new List<int> { 1, 2, 3 };
var obsList = nativeList.ToObservableList(); // 扩展方法

// 2. 原生Dictionary → Ecng ConcurrentObservableDictionary
var nativeDict = new Dictionary<int, string> { {1, "A"}, {2, "B"} };
var concObsDict = nativeDict.ToConcurrentObservableDictionary();

// 3. IEnumerable<T> → Ecng CyclicBuffer<T>
var array = new[] { 1, 2, 3 };
var buffer = array.ToCyclicBuffer(3); // 容量为3,填充数组元素

// 4. Ecng集合 → 原生集合
var ecngList = new ObservableList<int> { 1, 2, 3 };
var nativeList2 = ecngList.ToList(); // 转为原生List
var nativeDict2 = concObsDict.ToDictionary(); // 转为原生Dictionary

2. 高性能枚举与安全操作(并发场景避坑)

并发场景下,直接枚举集合可能会因"枚举时修改集合"导致 InvalidOperationException,Ecng 提供了两种安全枚举方式,兼顾性能与安全性。

csharp 复制代码
var set = new ConcurrentHashSet<int> { 1, 2, 3, 4, 5 };

// 方式1:使用SafeEnumerable()(推荐,获取集合快照,无锁)
// 适合只读枚举,不修改集合的场景,性能最优
foreach (var item in set.SafeEnumerable()) 
{
    Console.WriteLine(item);
}

// 方式2:使用Lock()手动控制(适合枚举时修改集合的场景)
// Lock()返回IDisposable,using结束自动释放锁,避免死锁
using (set.Lock())
{
    foreach (var item in set)
    {
        if (item % 2 == 0)
        {
            set.Remove(item); // 枚举时修改集合,安全无异常
        }
    }
}

// 注意:避免直接枚举并发集合(错误示例)
// foreach (var item in set) { set.Remove(item); } // 可能抛出异常

3. 自定义比较器(适配业务场景)

Ecng 集合默认使用 EqualityComparer<T>.Default 进行元素比较,但实际业务中,常需按对象的某个属性(如ID)进行比较,此时可自定义比较器,灵活适配业务需求。

csharp 复制代码
// 1. 定义业务实体
public class Student
{
    public int Id { get; set; }    // 唯一标识
    public string Name { get; set; } // 姓名(可重复)
}

// 2. 自定义比较器:按Id比较(忽略Name差异)
public class StudentIdEqualityComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x == null && y == null) return true;
        if (x == null || y == null) return false;
        return x.Id == y.Id; // 核心:按Id判断是否相等
    }

    public int GetHashCode(Student obj)
    {
        return obj.Id.GetHashCode(); // 哈希值基于Id计算
    }
}

// 3. 使用自定义比较器创建Ecng集合
var comparer = new StudentIdEqualityComparer();
var studentSet = new ConcurrentHashSet<Student>(comparer);

// 4. 测试:Id相同,Name不同,视为重复元素
studentSet.Add(new Student { Id = 1, Name = "Alice" });
studentSet.Add(new Student { Id = 1, Name = "Bob" }); // 重复,添加失败

Console.WriteLine(studentSet.Count); // 输出:1(仅保留一个Id=1的元素)

4. 与 MVVM 结合(WPF/Blazor 实战)

ObservableList<T>ConcurrentObservableDictionary<TKey, TValue> 是 MVVM 模式的最佳伙伴,无需额外继承 ObservableObject 基类,即可实现集合的自动通知,简化 ViewModel 代码。

csharp 复制代码
// ViewModel 示例(WPF)
public class MainViewModel
{
    // 可观测集合,自动实现INotifyCollectionChanged
    public ObservableList<Student> Students { get; } = new ObservableList<Student>();

    // 并发可观测字典,适配多线程更新UI
    public ConcurrentObservableDictionary<int, string> ClassNames { get; } 
        = new ConcurrentObservableDictionary<int, string>();

    public MainViewModel()
    {
        // 初始化数据
        Students.AddRange(new[]
        {
            new Student { Id = 1, Name = "Alice" },
            new Student { Id = 2, Name = "Bob" }
        });

        ClassNames.TryAdd(1, "计算机1班");
        ClassNames.TryAdd(2, "计算机2班");
    }

    // 模拟多线程更新集合(UI自动响应)
    public void AddStudent(Student student)
    {
        // 多线程环境下安全添加,同时触发UI更新
        Students.Add(student);
    }
}

// XAML 绑定示例(WPF)
// <ListBox ItemsSource="{Binding Students}" DisplayMemberPath="Name" />
// <ComboBox ItemsSource="{Binding ClassNames}" DisplayMemberPath="Value" />

五、实战场景:完整案例(高性能日志系统)

结合 Ecng.Collections 的核心数据结构,实现一个 线程安全、高性能、固定容量、UI 实时更新 的日志收集系统,贴合游戏服务器、后端服务的实际需求。

场景需求

  • 多线程并发写入日志(如业务线程、异步线程同时写日志)。

  • 日志总量固定,保留最新 1000 条,满了自动覆盖最旧日志。

  • 快速查询某类日志(如错误日志)是否存在,用于告警判断。

  • 日志变更时,自动通知 UI 实时显示,无需手动刷新。

实现代码

csharp 复制代码
using Ecng.Collections;
using Ecng.Common;
using System.Collections.Specialized;

// 1. 日志模型
public enum LogType { Info, Warning, Error }
public class LogEntry
{
    public LogType Type { get; set; }
    public string Message { get; set; }
    public DateTime Time { get; set; } = DateTime.Now;
}

// 2. 高性能日志服务(核心实现)
public class LogService
{
    // 循环缓冲区:固定容量1000,存储最新日志,自动覆盖旧日志
    private readonly CyclicBuffer<LogEntry> _logBuffer;
    
    // 并发HashSet:快速判断某类日志是否存在(用于告警)
    private readonly ConcurrentHashSet<LogType> _activeLogTypes;
    
    // 可观测列表:用于UI绑定,实时显示日志
    public ObservableList<LogEntry> Logs { get; }

    // 线程安全锁(用于同步缓冲区与可观测列表)
    private readonly object _lockObj = new object();

    public LogService(int maxLogCount = 1000)
    {
        _logBuffer = new CyclicBuffer<LogEntry>(maxLogCount);
        _activeLogTypes = new ConcurrentHashSet<LogType>();
        Logs = new ObservableList<LogEntry>();
    }

    // 线程安全的写日志方法(核心API)
    public void WriteLog(LogType type, string message)
    {
        var entry = new LogEntry
        {
            Type = type,
            Message = message
        };

        lock (_lockObj)
        {
            // 1. 写入循环缓冲区(自动覆盖旧日志)
            _logBuffer.Push(entry);
            
            // 2. 更新活跃日志类型(用于告警判断)
            _activeLogTypes.Add(type);
            
            // 3. 更新UI绑定的可观测列表(保持与缓冲区一致)
            Logs.Add(entry);
            // 限制UI列表大小,避免内存溢出
            if (Logs.Count > _logBuffer.Capacity)
            {
                Logs.RemoveAt(0);
            }
        }
    }

    // 快速查询某类日志是否存在(O(1)时间复杂度)
    public bool HasLogType(LogType type)
    {
        return _activeLogTypes.Contains(type);
    }

    // 获取所有日志(线程安全快照)
    public LogEntry[] GetAllLogs()
    {
        using (_logBuffer.Lock())
        {
            return _logBuffer.ToArray();
        }
    }

    // 清空所有日志
    public void ClearLogs()
    {
        lock (_lockObj)
        {
            _logBuffer.Clear();
            _activeLogTypes.Clear();
            Logs.Clear();
        }
    }
}

// 3. 调用示例(多线程测试)
public class Program
{
    public static void Main()
    {
        var logService = new LogService(1000);

        // 模拟多线程并发写日志(10个线程,每个线程写100条)
        Parallel.For(0, 10, threadId =>
        {
            for (int i = 0; i < 100; i++)
            {
                var logType = (LogType)(i % 3); // 循环生成3种日志类型
                logService.WriteLog(logType, $"线程{threadId}:日志{i},类型{logType}");
            }
        });

        // 测试查询功能
        bool hasError = logService.HasLogType(LogType.Error);
        Console.WriteLine($"是否存在错误日志:{hasError}");

        // 测试获取所有日志
        var allLogs = logService.GetAllLogs();
        Console.WriteLine($"当前日志总数:{allLogs.Length}"); // 输出1000(固定容量)

        // UI 绑定(WPF/Blazor)
        // var vm = new MainViewModel { LogService = logService };
        // 界面绑定 LogService.Logs 即可实时显示日志
    }
}

六、避坑指南与最佳实践(深度重点)

Ecng.Collections 用法简洁,但在高性能、高并发场景下,若使用不当,会导致性能损耗或异常,以下是企业级开发的避坑要点和最佳实践。

1. 集合选型避坑(关键!)

不同集合适配不同场景,选错集合会导致性能瓶颈,精准选型是关键:

  • 多线程去重、快速查找 → 选 ConcurrentHashSet<T>(O(1) 查找,原子操作)。

  • MVVM 集合绑定、UI 实时更新 → 选 ObservableList<T>(批量操作优化,事件可控)。

  • 固定大小缓存、日志/消息存储 → 选 CyclicBuffer<T>(内存固定,自动覆盖)。

  • 频繁在列表中间增删 → 选 LinkedList2<T>(O(1) 节点操作,比 List 高效)。

  • 多线程+UI绑定的字典场景 → 选 ConcurrentObservableDictionary(并发安全+可观测)。

  • 通用只读场景 → 优先用原生集合(ListHashSet),避免过度封装。

2. 性能注意事项

  • 避免不必要的集合转换:频繁在原生集合与 Ecng 集合之间转换,会增加内存开销和性能损耗,尽量在初始化时确定集合类型。

  • 并发集合的锁控制:ConcurrentHashSetConcurrentObservableDictionary 已实现原子操作,无需额外加锁;但复杂批量操作(如枚举+修改),需使用 Lock() 手动控制,避免竞争。

  • ObservableList 事件优化:频繁批量修改时,先调用 SuspendNotifications() 暂停事件,修改完成后调用 ResumeNotifications(),减少 UI 刷新次数。

  • 循环缓冲区容量设置:根据业务需求合理设置容量,容量过大浪费内存,过小会频繁覆盖,建议结合日志/缓存的实际保留需求设置(如1000条、10000条)。

3. 常见异常规避

  • 枚举异常:并发场景下,避免直接枚举 Ecng 并发集合,优先使用 SafeEnumerable()Lock() 安全枚举。

  • 比较器异常:自定义比较器时,需确保 EqualsGetHashCode 逻辑一致(如按 Id 比较,哈希值也需基于 Id),否则会导致集合查找、去重异常。

  • 内存溢出:ObservableList 用于 UI 绑定时,需限制列表大小,避免无限制添加元素(如日志系统中,与循环缓冲区容量保持一致)。

4. 通用最佳实践

  • 封装复用:将常用集合操作(如集合转换、安全枚举、批量更新)封装为工具类,避免重复代码,统一维护。

  • 版本兼容:Ecng.Collections 版本更新较快,需确保项目中使用的版本与 .NET 版本兼容(推荐使用最新稳定版,适配 .NET 6+)。

  • 日志与监控:在高频操作的集合中,添加日志记录(如循环缓冲区覆盖、并发集合操作失败),便于排查问题;高并发场景下,监控集合操作耗时,优化性能瓶颈。

  • 优先使用扩展方法:Ecng 提供的扩展方法(如 ToObservableListSafeEnumerable)经过性能优化,比手动实现更高效、更安全。

七、总结

Ecng.Collections 的核心价值是 "填补原生集合短板,优化高性能、高并发场景体验"。它不是对原生集合的替代,而是精准补充,让 C# 开发者在面对特殊数据结构、并发操作、UI 绑定等场景时,无需手动封装,直接使用成熟、高效的组件。

掌握 Ecng.Collections 的关键:精准选型(根据场景选择合适的集合)、熟练使用核心 API、规避并发与性能坑,结合实战场景灵活运用。对于游戏服务器、高频交易系统、后端并发服务等高性能需求的项目,Ecng.Collections 能大幅提升开发效率,降低维护成本,优化系统性能。

扩展建议:深入学习 Ecng 生态的其他类库(如 Ecng.Logging、Ecng.Serialization),实现集合与日志、序列化的无缝集成;同时关注 Ecng 官方文档,了解最新的集合扩展与性能优化特性。

相关推荐
m0_528174452 小时前
C++中的策略模式实战
开发语言·c++·算法
Eiceblue2 小时前
C# 中如何设置 Word 文档页面?(页面大小、边距、方向自动化控制)
c#·自动化·word·visual studio
计算机安禾2 小时前
【C语言程序设计】第30篇:指针与字符串
c语言·开发语言·c++·算法·visualstudio·visual studio code·visual studio
信奥胡老师2 小时前
GESP 2026年3月C++三级(二进制回文串)
开发语言·c++·算法
Allen_LVyingbo2 小时前
GTC2026前瞻(二)Agentic AI 与开源模型篇+(三)Physical AI 与机器人篇
开发语言·人工智能·数学建模·机器人·开源·知识图谱
liuyao_xianhui2 小时前
动态规划_最长递增子序列_C++
java·开发语言·数据结构·c++·算法·链表·动态规划
程序员爱酸奶2 小时前
Java常用设计模式
java·开发语言·设计模式
Meepo_haha2 小时前
Go基础之环境搭建
开发语言·后端·golang
2401_853576502 小时前
并行算法在STL中的应用
开发语言·c++·算法