2008-11-21 63 views
27

是否可以在設計時聲明一個通用實例而不知道類型?動態聲明一個通用類型實例

例子:

Int i = 1; 
List<typeof(i)> list = new List<typeof(i)>(); 

其中i的類型,可以是任何東西,而不必做:

List<int> list = new List<int(); 

回答

43

如果你不知道類型的編譯時間,但你想要的實際類型(即不List<object>你在一個通用的方法/類型與合適的類型參數不是,那麼你必須使用反射。

爲了使反射更簡單,我有時在自己的代碼中引入了一個新的泛型類型或方法,所以我可以通過反射來調用它,但是之後,你只需要使用正常的泛型。例如:

object x = GetObjectFromSomewhere(); 
// I want to create a List<?> containing the existing 
// object, but strongly typed to the "right" type depending 
// on the type of the value of x 
MethodInfo method = GetType().GetMethod("BuildListHelper"); 
method = method.MakeGenericMethod(new Type[] { x.GetType() }); 
object list = method.Invoke(this, new object[] { x }); 

// Later 

public IList<T> BuildListHelper<T>(T item) 
{ 
    List<T> list = new List<T>(); 
    list.Add(item); 
    return list; 
} 

當然,你不能做一個可怕的很多與列表之後,如果你不知道類型...這就是爲什麼這種事情經常摔倒。並非總是如此 - 我已經在一些場合使用過類似的東西,類型系統並不能完全讓我表達靜態需要的所有東西。

編輯:請注意,雖然我在上面的代碼中調用Type.GetMethod,如果你要執行它很多,你可能只想調用它一次 - 畢竟,該方法不會改變。你也許可以把它變成靜態的(你可以在上面的例子中),你可能也想把它變成私有的。我將它作爲一個公共實例方法,以簡化示例代碼中的GetMethod調用 - 否則您需要指定適當的綁定標誌。

+0

你可以返回一個非泛型的IList(它受List <>支持),那麼返回的列表將被使用。 – configurator 2008-11-28 18:42:25

1

我認爲你將能夠做的最好的是一樣的東西這個:

static void Main(string[] args) 
{ 
    int i = 1; 
    var thelist = CreateList(i); 
} 

public static List<T> CreateList<T>(T t) 
{ 
    return new List<T>(); 
} 
+1

這依賴於編譯器能夠推斷出類型 - 這意味着它必須知道在編譯時的類型。 – 2008-11-21 07:10:41

1

如果你不知道在設計時的類型,我會說你有對象的列表(對於所有其他類型的基類)。

List<object> list = new List<object>(); 
+1

不,您仍然可以創建適當類型的列表,並將其傳遞給可能能夠以正確類型進行類型轉換並以靜態類型方式處理的類型。僅僅因爲一段代碼不知道類型並不意味着*沒有*知道類型。 – 2008-11-21 07:12:14

1

您還可以使用Activator.CreateInstance。示例代碼片段:

public class BaseRepository<T> where T : DataContext 
{ 
    protected T _dc; 

    public BaseRepository(string connectionString) 
    { 
     _dc = (T) Activator.CreateInstance(typeof(T), connectionString); 
    } 

    public void SubmitChanges() 
    { 
     _dc.SubmitChanges(); 
    } 
} 
0

查看類似問題的答案"Dynamically Create a Generic Type for Template"。唯一的區別是它們從命令行生成類型,其餘的應該能夠適應您的需求。

順便說一句,你不能調用的typeof上的一個實例 - 獲得一個實例的類型(例如「我」叫的GetType():

Type intType = i.GetType(); 
0

如果你仍然想輸入.Add(),.Remove(),做foreach等等,你可以把List當做一個普通的「舊」System.Collections.IList, ,因爲這個接口很幸運地被List < T>。

由於所有其他發佈的答案對這個問題顯示幾乎所有其他可能的方式來創建列表的實例< T>動態, 我會顯示最後一種方法來做到這一點。 我個人在創建通用實例時使用這種方法,當我在編譯時並不知道類型, 和類型必須作爲字符串傳遞,可能來自應用程序配置文件。 在這個例子中,T是System.String爲了簡單,但它可以是任何東西:

Type T = typeof (string); // replace with actual T 
string typeName = string.Format (
    "System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName); 

IList list = Activator.CreateInstance (Type.GetType (typeName)) 
    as IList; 

System.Diagnostics.Debug.Assert (list != null); // 

list.Add ("string 1"); // new T 
list.Add ("string 2"); // new T 
foreach (object item in list) 
{ 
    Console.WriteLine ("item: {0}", item); 
}