GameFrameworkModule.cs总共就这点东西首先它是一个抽象类自己默认实现的是Priority默认就给它0可以被覆写为其他的但是不写就是0。然后Update和Shutdown留给实现类GameFrameworkModule只作为一个父类来用大部分时候都用于里氏替换配合GameEntry。GameFrameworkLinkedList.cs重点来了。GF就是用LinkedList这种模式来工作的因为需要某一个模块时候这个模块只需要知道自己的上一个和下一个是谁就行了直接存着下一节点的地址而且遍历也是一个一个遍历所以对于遍历也很方便。不用List首先是因为List也需要扩容而链表就不用了它地址不是连续的而且对于加减某一个节点非常方便也不需要List那样内存搬家的操作。首先它是一个sealed密封类防止被继承修改。然后指定泛型T也就是指定T为什么类型它内部维护的的LinkedList中的每一个节点就的值的类型就是什么。它集成ICollection, IEnumerable, ICollection, IEnumerable首先因为需要让它能被foreach所以肯定得能从它身上获得到迭代器所以继承IEnumerable但是它是一个类如果迭代器是class那么每foreach一次就会实例化一个继承了IEnumerator的子类那么每一帧都遍历一次的话就会在堆上创建很多仅仅是因为遍历就占用堆内存的实例所以这里没有让GameFrameworkLinkedList这个类作为迭代器的实现类只是让它能够获取到一个迭代器。然后继承ICollection如果框架内部或外部引用了某些接收 ICollection 参数的旧方法实现了这个接口后GameFrameworkLinkedList 就可以直接传入无需额外封装成数组或 List另外Unity在Inspector上如果用ICollection来约束的话也可以传入当前类型。m_LinkedList是GameFrameworkLinkedList这个类主要封装的一个链表里面放了所有正在使用的节点每一个Node的Value的类型是创建GameFrameworkLinkedList模块时T传入的类型。m_CachedNodes是一个Node的缓存池意思就是当Node不需要的时候放入这个缓存池里需要的时候再从这个缓存池里取取出来在对参数进行设置直接减少Node的创建数量如果频繁创建销毁节点因为是Class那么开销很大但是用池技术的话就可以大幅度减少在堆上的开销避免GC造成的卡顿。首先继承ICollection需要实现这里这个SyncRoot相当于将m_LinkedList自身返回出去了当做线程锁对象来用但是不建议用是ICollection接口要求。然后IsSynchronized返回当前m_LinkedList是否是线程安全的IsSynchronized 永远返回 false。结论是不要用这两个。获取迭代器实例调用了下面这个方法返回的就是创建出来的Enumerator这个对象(它是struct不是class后面说)IEnumerable.GetEnumerator是因为ICollection也继承了IEnumerable但是ICollection是接口没有具体实现所以需要实现ICollection里的GetEnumerator方法然后第二个GetEnumerator()方法是一个内部具体处理的方法让这些接口必须实现的方法来调用。然后继承ICollection需要实现定义怎么往集合里添加元素。定义怎么清理集合的元素。定义怎么比较集合的元素。定义获取迭代器让其能够被foreach。定义怎么移除某个元素。定义怎么将下标后的内容拷贝到对应泛型的array里。然后就是剩下的IEnumerable和IEnumerable这两个接口了对应的函数了:只有获取迭代器方法他们内部都调用的是GetEnumerator这个方法这个在上面已经看过了里面就是new了一个Enumerator。说完了接口强制要求实现的函数再看看这个类里其他的函数或者属性返回缓存节点队列的数量返回第一个节点返回最后一个节点。先看两个比较重要的方法AcquireNode和ReleaseNodeAcquireNode是创建节点创建节点如果发现缓存节点队列不是空的那么就直接从缓存节点队列取一个然后初始化设置value再返回出去。如果缓存节点队列是空的那么直接new一个节点给到node然后返回。然后是这个ReleaseNode就是将传递进来的节点的Value设置成默认值然后加到缓存节点队列里等后续用。直接减少节点创建数量。然后就没有其他函数了之后就是包含在GameFrameworkLinkedList里的一个内部结构体Enumerator。继承IEnumerator,IEnumerator也就是说在之前的GetEnumerator的时候返回的对象就是这个结构体对象。首先制作一个迭代器要实现迭代器 对于某个集合的引用。比如这里让迭代器引用的集合类型就是LinkedList.Enumerator也就是直接引用了一个Enumerator对象(或者说直接将具体的迭代器封装了一下因为C#内置的LinkedList.Enumerator在获取迭代器时候也是通过struct制作的)作为要遍历的引用的对象。然后构造函数就是将LinkedList的那个对象传递进来然后从这个LinkedList上获得struct类型的迭代器给到自身等着遍历用。首先得实现这两个接口对应的Current属性其实具体实现就是从LinkedList这个struct对象里再获取Current。然后是这个释放依旧是调用引用对象的。最后是MoveNext和Reset不过Reset函数需要注意m_Enumerator的类型是LinkedList.Enumerator需要强转成IEnumerator这当然可以转换因为LinkedList内部的Enumerator也继承了IEnumerator。所以这个GF框架的GameFrameworkLinkedList相当于仿照LinkedList来制作并且内部包装维护了一个LinkedList对象然后加上了一些自己需要的内容比如CacheNode什么什么的这些重新封装了一遍LinkedList减少节点的创建。另外这里需要说一下因为结构体的成员在内存中的排列是按照声明的时候的顺序的比如一个byte一个int一个byte总共三个变量如果不声明Auto那么它们在内存中的所占用的内存空间就是12个字节因为在32/64位系统上int要求4字节对齐也就是比如下标0给到第一个byte成员然后填充三个字节保持字节对齐然后再写int的那四个字节然后再写byte然后再填充三个字节这样最终就有6个字节用来做了填充。如果加了Auto的话允许运行时候重新排列字段顺序减少填充空隙。比如会变成前四个字节直接给到int然后下一个字节给byte成员再下一个字节给byte成员然后再填充两个字节保持4字节的对齐总共占用8字节。缺点就是排序有可能不确定如果存在和其他语言交互必须使用[StructLayout(LayoutKind.Sequential)]其实不加的话也是这个特性所以这种感觉不建议使用。如果只考虑在托管代码内部使用并且高频创建的这种结构体就可以使用。还有一种手动设置偏移量的方式关于需要多次作为临时使用的对象看看能不能用结构体比如这里的IEnumerator对象遍历完就不用了如果是类对象那么就浪费了一个堆空间的位置所以适合用栈。另外StructLayout重排对临时不需要其他语言互相操作的结构体可以用否则别用。面相接口编程比如这个LinkedList类它的大部分函数都是接口要求的比如SyncRoot这个属性其实不建议使用但是接口要求了写上也无妨。GameFrameworkAction.cs这个脚本里面都是无返回值的委托专门设定的有不同参数的委托而且通过in来修饰泛型让对应类型只能成为参数。大概瞄一眼。GameFrameworkFunc.cs和GameFrameworkAction.cs一样是有返回值的委托。GameFrameworkException.cs一个抛出类可以在try catch时候判断是否是这个类型的抛出。直接继承Exception。构造函数直接base了父类Exception的构造函数目的只是封装一层用来在try catch时候判断是否有抛出和抛出的类型是否是GameFrameworkException因为如果判断到是GameFrameworkException类型的错误的话就很方便能明白是逻辑和框架部分的问题了。就像看到Unity里OutOfRange一眼就能明白抛出了个溢出的意思一样而且对于try catch里针对某些抛出也可以继续执行后面finally的内容。先到这儿感觉这个系列要变得很庞大起来了…若有问题感谢指出