2015-12-23 201 views
0

我有一个简单的方法,我需要将Type变量传递给期望泛型的另一个第三方方法调用。如果我强制键入类型,但不通过将其作为参数传递,它会正常工作。Cast Type to Generic

从我看过的文章看来,这是不可能的,特别是如果需要高性能的话。

这种理解是否正确?

这工作:

public IEntity Get(Type type, object objectID) 
    { 
     if(_store == null) InitDBConnection(); 
     using (var session = _store?.OpenSession()) 
     { 
      return session?.Load<ContentBlock>(objectID.ToString()); 
     } 
    } 

这不:

public IEntity Get(Type type, object objectID) 
    { 
     if(_store == null) InitRavenConnection(); 
     using (var session = _store?.OpenSession()) 
     { 
      return session?.Load<type>(objectID.ToString()); 
     } 
    } 
+0

这两种泛型和反射都是类似的朋友最好的解决方案,考虑在会话对象中添加'.Load(Type type,object objectID)',否则你将不得不使用反射来调用这个方法。通常使用这种特定类型的代码,我认为这些代码最终会从数据库中加载某些东西,最终它会使用反射来获取属性。基本上你会从Type到T,然后从T返回Type。这两种转换都是昂贵的,可以考虑消除这种需求。 –

回答

1

调用通过反射泛型方法将花费一些性能,但它是可能的。

要做到:

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(); 
     } 
    } 
} 
+0

这几乎是我所要去的地方。即使是4倍速减速也是如此,所以不得不这么做 – GreatSamps