恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Morpeh Filter 扩展与生命周期管理:IFilterExtension 与 Filter.Dispose 完整实战指南
首页
资讯中心
/
Morpeh Filter 扩展与生命周期管理:IFilterExtension 与 Filter.Dispose 完整实战指南
Morpeh Filter 扩展与生命周期管理:IFilterExtension 与 Filter.Dispose 完整实战指南
发布时间:2026/8/25 17:25:11
Morpeh Filter 扩展与生命周期管理IFilterExtension 与 Filter.Dispose 完整实战指南【免费下载链接】morpeh ECS Framework for Unity Game Engine and .Net Platform项目地址: https://gitcode.com/gh_mirrors/mo/morpehMorpeh 是面向 Unity 与 .NET 平台的高性能 ECS实体-组件-系统框架Filter 是其中最核心的实体查询工具。本指南带你用 IFilterExtension 接口封装可复用的查询条件并用 Filter.Dispose 精确管理 Filter 生命周期——只需几行代码就能告别重复查询与内存泄漏。一、为什么需要 Filter 扩展用 Morpeh 写过系统后你大概率遇到过这两个烦恼重复编写查询World.Filter.WithTranslation().WithRotation().WithScale()这串条件在 10 个系统里复制了 10 遍Filter 越积越多Filter 是引用类型会一直持有对原型集Archetype的引用。系统停止工作后如果忘记清理它就赖在 World 里拖累后续的原型迁移。Morpeh 为此提供了两个机制痛点解决方案源码位置查询条件复用IFilterExtensionFilterBuilder.ExtendT()IFilterExtension.cs过滤器生命周期管理Filter.Dispose()Filter.cs先认识一下项目的组件与系统是怎么创建的Filter 就诞生在这样的世界里二、4 行代码编写一个 IFilterExtension接口本体只有 1 个方法完整源码见 IFilterExtension.cspublic interface IFilterExtension { FilterBuilder Extend(FilterBuilder rootFilter); }它的含义很直白接收一条半成品查询链返回一条加长版查询链。注意扩展必须是struct由ExtendT()的泛型约束决定内部通过default(T)直接调用零堆分配。以 README 中的经典示例Transform 组件组为例只需 4 行// 把同时拥有 Translation Rotation Scale 的实体封装成一条可复用查询 public struct TransformFilter : IFilterExtension { public FilterBuilder Extend(FilterBuilder rootFilter) rootFilter.WithTranslation().WithRotation().WithScale(); }进阶用法Morpeh 支持IAspect组件分组与IFilterExtension查询复用合二为一。让Transform结构体同时实现两个接口就能一个类型既管数据访问又管查询定义这是 README 官方推荐的组合姿势官方文档可参考 README.md。三、Extend ()把扩展插进查询链任意位置调用入口是FilterBuilder上的泛型方法实现在 FilterBuilder.cspublic FilterBuilder ExtendT() where T : struct, IFilterExtension { var newFilter default(T).Extend(this); return newFilter; }关键点ExtendT()返回一个全新的 FilterBuilder链上还能继续With/Without/ 再Extend顺序完全自由private Filter filter; public void OnAwake() { // 在扩展的前后都能自由追加条件 this.filter this.World.Filter .WithHealthComponent() // 前置条件 .ExtendTransformFilter() // 插入封装好的 Transform 三件套 .WithoutDeadComponent() // 后置排除 .Build(); }这样写的好处当移动系统的查询需要调整时只改TransformFilter一处所有使用它的系统全部生效。四、Build() 缓存机制相同条件自动复用同一个 FilterBuild()并不是每次都 new 一个 Filter。它内部有两道机制源码见 FilterBuilder.cs 的Build()与CompleteBuild()世界级查找表filtersLookup以 (包含条件哈希, 排除条件哈希) 为键相同条件组合的Build()直接命中缓存返回同一个 Filter 实例上下文对象池ContextPoolFilterBuilder 内部的with/without数组从对象池租借避免每次构建查询都分配内存。由此得出两条实战结论同条件多处查询 同一个 Filter多个系统持有的引用指向同一实例生命周期必须协调FilterBuilder 是一次性的Build()之后或分支复用后再调用WithT()会抛出FilterBuilderReuseException。五、Filter.Dispose()把 Filter 从 World 中彻底蒸发官方文档对 Dispose 的定义见 README.md Filter Disposing 一节让 Filter 从 World 中彻底消失仿佛它从未存在过。拆开 Filter.cs 的Dispose()源码它做了 5 件事步骤清理动作意义1从所有关联 Archetype 中RemoveFilter(this)断开原型集→过滤器反向引用2从componentsFiltersWith/componentsFiltersWithout索引中移除后续实体迁移不再扫描这个 Filter3从filtersLookup缓存中删除该条目同条件再次 Build 时会新建而非复用已销毁实例4Array.Clear全部内部数组、清空 BitSet释放托管内存5Filter ID 压回freeFilterIDs栈filterCount--ID 可被未来新 Filter 回收复用其中第 3 步最容易被忽略因为 Build 缓存的存在先 Dispose 再 Build 同条件会安静地创建一个新 Filter——这是特性不是 Bug但也意味着不要持有已 Dispose Filter 的引用继续遍历。⚠️ 两条必须记住的警告警告 1全局生效Filter.Dispose移除的是 World 中该 Filter 的所有实例而不仅是当前这次 Dispose 调用的持有者。系统 A 和系统 B 共享同一个缓存 Filter 时A 销毁它B 手里的引用就失效了。警告 2Burst / Native API开启了 Burst 时如果你用filter.AsNative()把 Filter 交给了 Job而 Job 尚未完成就调用了 Dispose编辑器会打印警告The filter youre trying to dispose of was used in the Native API. Ensure you dispose of it only after all jobs that used it have completed.见 Filter.cs 中MORPEH_BURST MORPEH_DEBUG分支。六、Filter 生命周期最佳实践结合ISystem的生命周期钩子推荐这样组织public class MovementSystem : ISystem { public World World { get; set; } private Filter filter; public void OnAwake() { // ① 初始化阶段构建 this.filter this.World.Filter.ExtendTransformFilter().Build(); } public void OnUpdate(float deltaTime) { // ② 热路径只遍历不改结构 foreach (var entity in this.filter) { // 移动逻辑... } } public void OnCleanup() { // ③ 清理阶段归还 this.filter.Dispose(); this.filter default; // 置空引用防止误用 } }速查清单✅ 在OnAwake中构建、OnCleanup中 Dispose成对出现✅ 需要 Burst 并行时先JobsComplete()再 Dispose❌ 不要在foreach (var e in filter)循环体内调用filter.Dispose()或World.Commit()❌ 不要对同一个 FilterBuilder 调用两次Build()。七、常见异常速查表异常触发场景定义位置FilterBuilderReuseExceptionBuilder 已 Build 过或发生分支复用FilterBuilderReuseException.csComponentExistsInFilterException同一组件同时出现在 With 与 Without 中ComponentExistsInFilterException.csFilterSourceSequenceIsEmptyException空 Filter 调用First()FilterSourceSequenceIsEmptyException.csFilterIndexOutOfRangeExceptionGetEntity(position)越界FilterIndexOutOfRangeException.cs八、源码地图模块路径说明扩展接口IFilterExtension.cs单方法接口查询复用入口构建器FilterBuilder.csWith / Without / Extend / Build / 上下文池过滤器本体Filter.csDispose 五步清理、原型集匹配、迭代器缓存与 ID 回收World.csfiltersLookup、freeFilterIDs单元测试FilterBuilderTests.cs、FilterMatchTests.cs复用校验与匹配逻辑验证官方文档README.mdFilter Extensions 与 Filter Disposing 章节总结IFilterExtension解决查询条件写一遍到处用Filter.Dispose解决用完就干净离场。前者靠 4 行 struct 封装后者靠 OnCleanup 里的一个调用——两者配合就是你的 Morpeh 项目里最省心的 Filter 生命周期管理方案。【免费下载链接】morpeh ECS Framework for Unity Game Engine and .Net Platform项目地址: https://gitcode.com/gh_mirrors/mo/morpeh创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考