XNA/ c#:实体工厂和类型(T)性能

本文关键字:类型 性能 工厂 实体 XNA | 更新日期: 2023-09-27 18:03:04

在我们的游戏(针对手机)中,我们有一些不同的实体类型,我正在编写一个工厂/存储库来处理新实体的实例化。每个具体实体类型都有自己的工厂实现,这些工厂由EntityRepository管理。

我想这样实现存储库:

Repository
{
 private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;
 public T CreateEntity<T> (params) where T : IEntity
 {
      return factoryDict[typeof(T)].CreateEntity() as T;
 }
}

使用示例
var enemy = repo.CreateEntity<Enemy>();

,但我关心的是性能,特别是与上面的typeof(T)操作有关。这是我的理解,编译器将无法确定T的类型,它将不得不在运行时通过反射确定,这是正确的吗?另一种选择是:

Repository
{
 private Dictionary <System.Type, IEntityFactory> factoryDict;
 public IEntity CreateEntity (System.Type type, params)
 {
      return factoryDict[type].CreateEntity();
 }
}

将被用作

var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);
在这种情况下,无论何时调用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;
    }

    private static Object ParamFunc(System.Type type)
    {
        var d = dict[type];
        return d;
    }

被称为

str = GenFunc<string>();

str = (String)ParamFunc(typeof(String));

。Paramfunc在性能上有了显著的提高(平均执行时间是GenFunc的60-70%),但测试还很初级,我可能遗漏了一些东西。特别是在泛型函数中如何执行强制类型转换。

有趣的是,与每次使用typeof()相比,在变量中"缓存"类型并将其传递给ParamFunc几乎没有(可忽略)的性能提高。

XNA/ c#:实体工厂和类型(T)性能

c#中的泛型不使用或不需要反射。

内部类型作为RuntimeTypeHandle值传递。typeof算子映射到Type.GetTypeFromHandle (MSDN)。不查看转子或单声道检查,我希望GetTypeFromHandle是0(1)并且非常快(例如:数组查找)。

所以在泛型(<T>)的情况下,你本质上是传递一个RuntimeTypeHandle到你的方法和调用GetTypeFromHandle 你的方法。在非泛型情况下,您首先调用GetTypeFromHandle,然后将结果Type传递到您的方法中。性能应该几乎相同-并且被其他因素大大超过,例如您分配内存的任何位置(例如:如果您使用params关键字)。

但它是一个工厂方法。它肯定不会每秒被调用超过几次吧?它是否值得优化?

你总是听说反射有多慢,但在c#中,实际上有快速反射和慢反射。typeof是快速反射——它基本上有方法调用的开销,这几乎是无穷小的。

我可以用牛排和龙虾晚餐打赌,这不会成为应用程序的性能瓶颈,所以不值得你(或我们)花时间去优化它。这句话已经说过无数次了,但有必要再说一遍:"过早优化是万恶之源。"

因此,完成应用程序的编写,然后使用配置文件来确定瓶颈在哪里。如果这是其中之一,那么并且只有在花时间优化它。告诉我你想在哪里吃晚饭。

同样,我上面的评论值得重复,所以你不必再花时间重新发明轮子:任何体面的IoC容器(如AutoFac)都可以自动[创建工厂方法]。如果您使用其中之一,则不需要编写自己的存储库,或编写自己的CreateEntity()方法,甚至不需要自己调用CreateEntity()方法—库会为您完成所有这些工作。