




Я думаю, лучшее, что вы сможете сделать, это что-то вроде этого:
static void Main(string[] args)
{
int i = 1;
var thelist = CreateList(i);
}
public static List<T> CreateList<T>(T t)
{
return new List<T>();
}
Совершенно уверен, что вы можете это сделать, их не нужно исправлять во время компиляции, как шаблоны в С ++.
Пример, похожий здесь: http://geekswithblogs.net/marcel/archive/2007/03/24/109722.aspx
Если вы не знаете тип во время разработки, я бы сказал, что у вас есть список ОБЪЕКТОВ (базовый класс для всех других типов).
List<object> list = new List<object>();
Нет, вы все равно можете создать список соответствующего типа и передать его чему-то, что может выполнить приведение к нужному типу и впоследствии работать с ним статически типизированным способом. Тот факт, что один фрагмент кода не знает типа, не означает, что ничего такого знает этот тип.
Вы также можете использовать 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();
}
}
Смотрите ответ на аналогичный вопрос «Динамическое создание универсального типа для шаблона». Единственная разница в том, что они генерируют тип из командной строки, остальное вы сможете адаптировать к своим потребностям.
Кстати, вы не можете вызвать typeof для экземпляра - чтобы получить тип экземпляра (например, "i" вызывает GetType ():
Type intType = i.GetType();
Если вы не знаете тип во время компиляции, но хотите фактический тип (т.е. не 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 в примере кода - в противном случае вам нужно было бы указать соответствующие флаги привязки.
Вы можете вернуть неуниверсальный IList (который поддерживается List <>), тогда возвращенный список будет полезен.
В этом случае было бы проще использовать ArrayList для начала.
ах, но добавление неправильного типа в коллекцию, когда она приведена как IList, все равно вызовет исключение о том, что это неправильный тип, не так ли?
Да, это вызовет исключение.
@JonSkeet, почему не что-то вроде List <type> list; разрешено в первую очередь? Это потому, что это противоречит парадигме статической типизации?
@Kakira: Да, цель дженериков - обеспечить безопасность типов во время компиляции. Какой был бы тип list[0]? Какой переменной вы могли бы ее присвоить?
12 лет спустя, и этот ответ мне снова помогает! Спасибо @JonSkeet
Если вы все еще хотите ввести .Add (), .Remove (), do foreach и т. д., Вы можете рассматривать List как обычный "старый" System.Collections.IList, поскольку этот интерфейс, к счастью, реализован List <T>.
И поскольку все другие опубликованные ответы на этот вопрос показывают практически все возможные способы динамического создания экземпляра List <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 );
}
Это зависит от того, что компилятор может определить тип, что означает, что он должен знать тип во время компиляции.