Можно ли объявить экземпляр родового без знания типа во время разработки?
Пример:
Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();
где тип я может быть чем угодно, вместо того, чтобы делать:
List<int> list = new List<int();
Можно ли объявить экземпляр родового без знания типа во время разработки?
Пример:
Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();
где тип я может быть чем угодно, вместо того, чтобы делать:
List<int> list = new List<int();
Если вы не знаете тип во время компиляции, но хотите фактический тип (т.е. не 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;
}
Конечно, после того, как вы не знаете тип, вы не сможете сделать много со списком, потому что это часто падает. Не всегда, хотя я несколько раз использовал что-то подобное выше, где система типов просто не позволяет мне выразить все, что мне нужно, статически.
EDIT: Обратите внимание, что хотя я вызываю Type.GetMethod в приведенном выше коде, если вы собираетесь его выполнить, вы, вероятно, захотите просто называть его один раз - в конце концов, метод не собирается изменение. Вы можете сделать его статическим (вы могли бы в случае выше), и вы, вероятно, захотите сделать его приватным. Я оставил его как метод публичного экземпляра для простоты вызова GetMethod в примере кода - вам нужно указать соответствующие флаги привязки в противном случае.
Я думаю, что лучшее, что вы собираетесь сделать, это что-то вроде этого:
static void Main(string[] args)
{
int i = 1;
var thelist = CreateList(i);
}
public static List<T> CreateList<T>(T t)
{
return new List<T>();
}
Если вы не знаете тип во время разработки, я бы сказал, что у вас есть список OBJECTS (базовый класс для всех других типов).
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();
}
}
Довольно уверен, что вы можете это сделать, их не нужно фиксировать во время компиляции, например, в С++.
Пример, подобный здесь: http://geekswithblogs.net/marcel/archive/2007/03/24/109722.aspx
См. ответ по аналогичному вопросу "Динамическое создание типового типа для шаблона" . Единственное различие заключается в том, что они генерируют тип из командной строки, а остальные вы должны быть способны адаптироваться к вашим потребностям.
В стороне вы не можете вызвать typeof для экземпляра - чтобы получить тип экземпляра (например, "i" вызвать GetType():
Type intType = i.GetType();
Если вы все еще хотите ввести .Add(),.Remove(), сделать 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 );
}