調用通過反射泛型方法將花費一些性能,但它是可能的。
要做到:
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。這兩種轉換都是昂貴的,可以考慮消除這種需求。 –