调用通过反射泛型方法将花费一些性能,但它是可能的。
要做到:
var result = session.Load<Entity>("abc");
与反思的样子:
MethodInfo method = typeof(Session).GetMethod("Load");
MethodInfo generic = method.MakeGenericMethod(typeof(Entity));
var result = generic.Invoke(session, new[] { "abc" });
正如你所提到的是慢了很多(慢20倍以上我的电脑)。
可以改善只是做了艰苦的工作一次,并缓存使用这样的事情反映了该类型的结果表现:
public class SessionInvoker
{
private Dictionary<Type, Func<Session, string, IEntity>> cache =
new Dictionary<Type, Func<Session, string, IEntity>>();
public IEntity Invoke(Type type, Session session, string id)
{
var invoker = cache.ContainsKey(type)
? cache[type]
: CreateAndCache(type);
return invoker(session, id);
}
private Func<Session, string, IEntity> CreateAndCache(Type type)
{
MethodInfo method = typeof(Session).GetMethod("Load");
MethodInfo generic = method.MakeGenericMethod(type);
var invoker = new Func<Session, string, IEntity>((session, id) =>
(IEntity)generic.Invoke(session, new[] { id }));
cache[type] = invoker;
return invoker;
}
}
这是我的电脑上不是调用方法慢4倍直接:
var result = invoker.Invoke(type, session, "abc");
下面的代码用于获取时序:
class Program
{
static void Main(string[] args)
{
var session = new Session();
var timer = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
{
var result = session.Load<Entity>("abc");
}
Console.WriteLine(timer.ElapsedMilliseconds);
timer = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
{
MethodInfo method = typeof(Session).GetMethod("Load");
MethodInfo generic = method.MakeGenericMethod(typeof(Entity));
var result = generic.Invoke(session, new[] { "abc" });
}
Console.WriteLine(timer.ElapsedMilliseconds);
timer = Stopwatch.StartNew();
MethodInfo method2 = typeof(Session).GetMethod("Load");
MethodInfo generic2 = method2.MakeGenericMethod(typeof(Entity));
for (int i = 0; i < 1000000; i++)
{
var result = generic2.Invoke(session, new[] { "abc" });
}
Console.WriteLine(timer.ElapsedMilliseconds);
timer = Stopwatch.StartNew();
var invoker = new SessionInvoker();
var type = typeof(Entity);
for (int i = 0; i < 1000000; i++)
{
var result = invoker.Invoke(type, session, "abc");
}
Console.WriteLine(timer.ElapsedMilliseconds);
Console.ReadLine();
}
public interface IEntity { }
public class Entity : IEntity { }
public class Session
{
public IEntity Load<T>(string id) where T : IEntity, new()
{
return new T();
}
}
}
这两种泛型和反射都是类似的朋友最好的解决方案,考虑在会话对象中添加'.Load(Type type,object objectID)',否则你将不得不使用反射来调用这个方法。通常使用这种特定类型的代码,我认为这些代码最终会从数据库中加载某些东西,最终它会使用反射来获取属性。基本上你会从Type到T,然后从T返回Type。这两种转换都是昂贵的,可以考虑消除这种需求。 –