在我们的游戏(针对移动设备)中,我们有一些不同的实体类型,我正在编写工厂/存储库来处理新实体的实例化.每个具体实体类型都有自己的工厂实现,这些工厂由EntityRepository管理.
我想这样实现存储库:
Repository
{
private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;
public T CreateEntity<T> (params) where T : IEntity
{
return factoryDict[typeof(T)].CreateEntity() as T;
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例
var enemy = repo.CreateEntity<Enemy>();
Run Code Online (Sandbox Code Playgroud)
但我关注的是性能,特别是与上述类型(T)操作有关.我的理解是编译器无法确定T的类型,它必须在运行时通过反射来确定,这是正确的吗?一种选择是:
Repository
{
private Dictionary <System.Type, IEntityFactory> factoryDict;
public IEntity CreateEntity (System.Type type, params)
{
return factoryDict[type].CreateEntity();
}
}
Run Code Online (Sandbox Code Playgroud)
将用作
var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,无论何时调用typeof(),类型都在手边并且可以由编译器确定(对吗?)并且性能应该更好.是否会有明显的差异?还有其他考虑吗?我知道我也可以在存储库中有一个像CreateEnemy这样的方法(我们只有几个实体类型),这样会更快,但我更愿意将存储库保持为实体 - 尽可能不知道.
编辑:
我知道这很可能不会成为瓶颈,我担心的是,如果可用的糖含量稍微低一些,那么就要浪费时间来反思.我认为这是一个有趣的问题:)
我做了一些基准测试,证明非常有趣(这似乎证实了我最初的怀疑).
使用我在http://blogs.msdn.com/b/vancem/archive/2006/09/21/765648.aspx上找到的性能测量工具 (它多次运行测试方法并显示平均时间等指标)我进行了一项基本测试,测试:
private static T GenFunc<T>() where T : class
{
return dict[typeof(T)] as T;
}
Run Code Online (Sandbox Code Playgroud)
反对
private static Object ParamFunc(System.Type type)
{
var d = dict[type];
return d;
}
Run Code Online (Sandbox Code Playgroud)
叫做
str = GenFunc<string>();
Run Code Online (Sandbox Code Playgroud)
VS
str = (String)ParamFunc(typeof(String));
Run Code Online (Sandbox Code Playgroud)
分别.Paramfunc显示了性能的显着提高(平均执行GenFunc所需的时间为60-70%),但测试非常简陋,我可能会遗漏一些东西.具体如何在通用函数中执行转换.
有趣的是,通过'缓存'变量中的类型并将其传递给ParamFunc与每次使用typeof()相比,可以获得很少(可忽略的)性能.
C#中的泛型不使用或需要反射.
内部类型作为RuntimeTypeHandle值传递.并且typeof运算符映射到Type.GetTypeFromHandle(MSDN).不看Rotor或Mono来检查,我希望GetTypeFromHandle是O(1)并且非常快(例如:数组查找).
所以在一般(<T>)情况下,你基本上传递RuntimeTypeHandle到您的方法,并呼吁GetTypeFromHandle 在你的方法.在您的非通用情况下,您GetTypeFromHandle首先调用然后将结果传递给Type您的方法.性能应该接近相同 - 并且大大超过其他因素,例如您分配内存的任何地方(例如:如果您使用params关键字).
但无论如何,这是一种工厂方法.当然它每秒不会被调用超过几次?它甚至值得优化吗?