我在下面有一个简单的玩具 ECS 对象实现。
DerefData(GameBehavior behavior)
方法的签名需要 GameBehavior
参数才能用作索引查找。
GameBehavior
值应由类型Flyable.BehaviorID
设置。但要知道,我们需要一个实例,这是行不通的,因为 deref 方法的目的是从泛型类型获取实例。
最好不使用反射,以便尽可能快。
可以重构为只需要
BaseGameObject<U> DerefData()
而不需要参数吗?
using System;
GameObject gameobj = new();
Flyable fdata = new Flyable { Velocity = 0d };
gameobj.AddBehavior(fdata);
var flightdata = gameobj.DerefData<Flyable>(GameBehavior.Flyable);
// i'd like to remove the parameter from this method signature.
// Which means we need access to IBehavior.BehaviorID,
// which is a 'type-level' property that in theory shouldn't need an object to lookup the value.
interface IBehavior
{
GameBehavior BehaviorID { get; }
}
struct Flyable : IBehavior
{
public GameBehavior BehaviorID => GameBehavior.Flyable;
public double Velocity;
}
[Flags]
enum GameBehavior : int
{
Flyable,
Burnable
}
class GameObject : BaseGameObject<IBehavior>{}
abstract class BaseGameObject<T> where T : IBehavior
{
T[] Items = new T[32]; // Max number of enum flags; this ECS is limited to at max 32 behaviors per game object
public U DerefData<U>(GameBehavior behavior) where U : T
{
return (U)Items[(int)behavior]; // We don't have an object instance to lookup behavior ID
}
public void AddBehavior<U>(U obj) where U : T
{
Items[(int)obj.BehaviorID] = obj; // we have an object instance to lookup BehaviorID
}
}
我自己的问题有答案,但我肯定会接受批评或其他答案
所讨论的方法是:
public U DerefData<U>(GameBehavior behavior) where U : T
{
return (U)Items[(int)behavior]; // We don't have an object instance to lookup behavior ID
}
我们重构如下:
public U DerefData<U>() where U : struct, T
{
return (U)Items[(int)new U().BehaviorID];
}
这需要在堆栈上分配预期行为类型的一次性结构。只要行为结构保持相对较小,堆栈分配应该很快并且不会逃逸到堆。
现在用法可以重构为
var flightdata = gameobj.DerefData<Flyable>();