2008-11-21 2 views

ответ

43

Если вы не знаете тип в времени компиляции, но вы хотите, фактический типа (т.е. не List<object>) и вы не в родовой методе/типа с соответствующим параметром типа, то вы должны использовать отражение.

чтобы сделать отражение проще , Я иногда вводил новый родовой тип или метод в свой собственный код, поэтому я могу назвать это отражением, но n после этого используйте обычные дженерики. Например:

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; 
} 

Конечно, вы не можете сделать очень много с перечнем потом, если вы не знаете тип ... вот почему такого рода вещи часто падает. Не всегда, хотя - я использовал что-то вроде выше в нескольких случаях, когда система типов просто не позволяет мне выразить все, что мне нужно, статически.

EDIT: Обратите внимание, что хотя я вызываю 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>.

И так как все остальные опубликованные ответы на этот вопрос показывают практически любой возможный способ создания экземпляра списка 0> < 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); 
} 
Смежные вопросы