2012-10-24 51 views
6

我想創建一個通用列表<>,其類型在運行時聲明。C#動態通用列表

我可以做以下事情,但由於它是動態的,我懷疑有速度的損失。我正在寫一個外來數據庫的包裝,所以速度至關重要。

List<dynamic> gdb = new List<dynamic>() 

我讀動態泛型類型this post,但不能讓它工作。具體而言,該對象不會顯示爲List,因此不具有添加方法。

Type ac; 

    switch (trail[dataPos].Type) 
    { 
     case GlobalsSubscriptTypes.Int32: 
      ac = typeof(System.Int32); 

      break; 
     case GlobalsSubscriptTypes.Int64: 
      ac = typeof(System.Int64); 

      break; 

     default: 
      ac = typeof(System.String); 

      break; 
    } 

    var genericListType = typeof(List<>); 
    var specificListType = genericListType.MakeGenericType(ac); 
    var gdb = Activator.CreateInstance(specificListType); 

如何獲得GDB顯示爲下列之一:

List<System.Int32> 
List<System.Int64> 
List<System.String> 
+1

它在這種情況下使用'List '可能會更容易。如果類型在編譯時不知道,那麼編譯時檢查泛型給你的幫助對你沒有任何幫助。 – Servy

+0

不是一個壞主意,但我希望列表被鍵入,因爲它將成爲查詢的一部分。 – IamIC

+0

列表怎麼樣? –

回答

5

一旦您使用了Activator.CreateInstance,您可以將結果轉換爲適當的類型。你可以使用IList例如:

var gdb = (IList)Activator.CreateInstance(specificListType); 
gdb.Add(1); 

注意上面拋出ArgumentException如果您要添加的類型不匹配的泛型類型。

+0

這是我正在尋找的答案。我投錯了地方。 – IamIC

+0

如果您打算只使用非通用接口,那麼您可以使用'List '並省去使用反射來創建列表的需要。 – Servy

+1

@Servy將要求每個int和long都被裝箱和拆箱,這是一個重大的性能問題。 – IamIC

1

在你的情況,gdb將永遠是一個System.Object,因爲任何類型的CreateInstance回報的對象。

您在這裏有幾個選項 - 您可以將其設置爲IList(非通用),因爲您知道List<T>實現此接口,並使用IList.Add

或者,你可以只聲明它dynamic,並使用動態綁定:

dynamic gdb = Activator.CreateInstance(specificListType); 

這將讓你寫你的代碼,如果是適當類型的List<T>,而呼叫將在運行時綁定通過動態綁定。

3

哦,gdb的正確類型。由於您確定運行時的類型,因此編譯器不知道它。因此,它的靜態類型爲object,並且不顯示Add方法。您有幾種選擇來解決這個問題:

  1. 將它轉換爲正確的類型:

    switch (trail[dataPos].Type) 
    { 
        case GlobalsSubscriptTypes.Int32: 
         ((List<int>) gdb).Add(...); 
         break; 
        ... 
        default: 
         ((List<String>) gdb).Add(...); 
         break; 
    } 
    
  2. 轉換爲公用超類型:

    ((System.Collections.IList) gdb).Add(...); 
    
  3. 使用動態調用:

    dynamic gdb = Activator.CreateInstance(specificListType); 
    gdb.Add(...); 
    
1

List<dynamic>編譯與List<object>完全相同的類型,對類型List<int>沒有速度損失,例如,超出了裝箱值類型。但是如果你打算投給IList,你仍然會有FYI的拳擊罰款。

可能會遇到麻煩的是調用Activator(反射方法),因爲直接調用構造函數的速度可能會明顯較慢。

有沒有這件事?除非您實際運行配置文件,否則您將無法知曉,因爲它總是取決於您的實際使用情況。

我最好的客人你真正想要做的是:

IList gdb; 

switch (trail[dataPos].Type) 
{ 
    case GlobalsSubscriptTypes.Int32: 
     gdb = new List<int>(); 
     break; 
    case GlobalsSubscriptTypes.Int64: 
     gdb = new List<long>(); 
     break; 
    default: 
     gdb = new List<string>(); 
     break; 
} 

此外,如果你真的需要做的操作,而不拳擊做出一個通用的輔助方法來完成所有的工作:

switch (trail[dataPos].Type) 
{ 
    case GlobalsSubscriptTypes.Int32: 
     return Helper<int>(trail[dataPos]); 
    case GlobalsSubscriptTypes.Int64: 
     return Helper<long>(trail[dataPos]); 
    default: 
     return Helper<string>(trail[dataPos]); 
} 
+0

感謝您的明確解釋。我喜歡助手的想法(儘管我沒有多少考慮它的代碼)。事實證明,由於多態性,我沒有選擇,只能在從數據庫中獲取值的類中使用動態。所以我假設我應該簡單地使用名單。 – IamIC

+1

@IanC我會用任何會產生最簡單代碼的東西,然後再擔心速度。 – jbtule