2015-12-23 248 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