开发者

XNA/C#: Entity Factories and typeof(T) performance

开发者 https://www.devze.com 2023-03-21 19:06 出处:网络
In our game (targeted at mobile) we have a few different entity types and I\'m writing a factory/repository to handle instantiation of new entities.Each concrete entity type has its own factory implem

In our game (targeted at mobile) we have a few different entity types and I'm writing a factory/repository to handle instantiation of new entities. Each concrete entity type has its own factory implementation and these factories are managed by an EntityRepository.

I'd like to implement the repository as such:

Repository
{
 private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;

 public T CreateEntity<T> (params) where T : IEntity
 {
      return factoryDict[typeof(T)].CreateEntity() as T;
 }
}

usage example

var enemy = repo.CreateEntity<Enemy>();

but I am concerned about performance, specifically related to the typeof(T) operation in the above. It is my understanding that the compiler would not be able to determine T's 开发者_如何学运维type and it will have to be determined at runtime via reflection, is this correct? One alternative is:

Repository
{
 private Dictionary <System.Type, IEntityFactory> factoryDict;

 public IEntity CreateEntity (System.Type type, params)
 {
      return factoryDict[type].CreateEntity();
 }
}

which will be used as

var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);

in this case whenever typeof() is called, the type is on hand and can be determined by the compiler (right?) and performance should be better. Will there be a noteable difference? any other considerations? I know I can also just have a method such as CreateEnemy in the repository (we only have a few entity types) which would be faster but I would prefer to keep the repository as entity-unaware as possible.

EDIT:

I know that this may most likely not be a bottleneck, my concern is just that it is such a waste to use up time on reflecting when there is a slightly less sugared alternative available. And I think it's an interesting question :)

I did some benchmarking which proved quite interesting (and which seem to confirm my initial suspicions).

Using the performance measurement tool I found at http://blogs.msdn.com/b/vancem/archive/2006/09/21/765648.aspx (which runs a test method several times and displays metrics such as average time etc) I conducted a basic test, testing:

private static T GenFunc<T>() where T : class 
    {

        return dict[typeof(T)] as T;
    }

against

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

called as

str = GenFunc<string>();

vs

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

respectively. Paramfunc shows a remarkable improvement in performance (executes on average in 60-70% the time it takes GenFunc) but the test is quite rudimentary and I might be missing a few things. Specifically how the casting is performed in the generic function.

An interesting aside is that there is little (neglible) performance gained by 'caching' the type in a variable and passing it to ParamFunc vs using typeof() every time.


Generics in C# don't use or need reflection.

Internally types are passed around as RuntimeTypeHandle values. And the typeof operator maps to Type.GetTypeFromHandle (MSDN). Without looking at Rotor or Mono to check, I would expect GetTypeFromHandle to be O(1) and very fast (eg: an array lookup).

So in the generic (<T>) case you're essentially passing a RuntimeTypeHandle into your method and calling GetTypeFromHandle in your method. In your non-generic case you're calling GetTypeFromHandle first and then passing the resultant Type into your method. Performance should be near identical - and massively outweighed by other factors, like any places you're allocating memory (eg: if you're using the params keyword).

But it's a factory method anyway. Surely it won't be called more than a couple of times per second? Is it even worth optimising?


You always hear how slow reflection is, but in C#, there is actually fast reflection and slow reflection. typeof is fast-reflection - it has basically the overhead of method call, which is nearly infinitesimal.

I would bet a steak and lobster dinner that this isn't going to be a performance bottleneck in your application, so it's not even worth your (or our) time in trying to optimize it. It's been said a million times before, but it's worth saying again: "Premature optimization is the root of all evil."

So, finish writing the application, then profile to determine where your bottlenecks are. If this turns out to be one of them, then and only then spend time optimizing it. And let me know where you'd like to have dinner.


Also, my comment above is worth repeating, so you don't spend any more time reinventing the wheel: Any decent IoC container (such as AutoFac) can [create factory methods] automatically. If you use one of those, there is no need to write your own repository, or to write your own CreateEntity() methods, or even to call the CreateEntity() method yourself - the library does all of this for you.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号