我有一些在运行时已知的类型的对象,我从数据库中读取和反序列化此对象。有用。现在我想将它添加到一些列表中:
private static List<T> generateList<T>()
{
List<T> lst = new List<T>();
return lst;
}
private void readObjects(System.Type objType)
{
var methodInfo = typeof(My.Serializator).GetMethod("DeserializeDb");
var genericMethod = methodInfo.MakeGenericMethod(objType1);
List<curType> currentList= generateList<curType>();
// ...read stream from database and convert it to object
while (_rs.Read())
{
var _objItem = genericMethod.Invoke(null, new[] { _streamedData });
currentList.Add(_objItem);
}
}
它无效。错误是:
curType是一个变量,但用作类型。
如果我将列表更改为:
List<object> currentList = new List<object>();
它会起作用。但我可以用泛型(T)代替对象类型吗?
答案 0 :(得分:1)
您可以通过Activator
轻松创建所需的列表类型,然后转换为IList
并使用它:
private IList readObjects(System.Type objType)
{
var listType = typeof(List<>).MakeGenericType(curType);
var list = (IList)Activator.CreateInstance(listType);
// ...
while (_rs.Read())
{
// ...
list.Add(_objItem);
}
}
list
将是List<YorActualType>
的实例。
更新
当您使用泛型参数声明方法时,它假定您在编译期间提供类型信息。否则你需要使用反射。
由于您在运行时提供类型信息(curType
可以保存任何类型信息),编译器不知道将使用什么样的类型,并且您不能声明您的方法返回具体的东西。只允许抽象。
让我用稍微疯狂但有示范性的例子来表明:
var types = new [] { typeof(int), typeof(string) };
var rand = new Random();
var list = readObjects(types[rand.Next(0,2)];
直到最后一刻,即使你不知道究竟会创建什么类型的列表。编译器也不知道。如果您没有向他提供类型,编译器将永远不知道应该使用什么类型。当您使用Type
时,它只告诉编译器一些类型为Type
的常规参数将在运行时传递给该方法。在编译期间没有数据可以推断出类型。该数据只能通过generic type parameters传递。
因此,有几种方法可以遵循:
在编译时提供您需要的确切类型
private List<T> readObjects<T>()
{
var objType = typeof(T);
var list = new List<T>();
// rest of code....
}
使用反射和基本类型
private IList readObjects(Type objType)
{
// rest of code with Activator and so on
}
以后的使用取决于您的需求。 如果您知道要使用的类型,只需转换:
var list = (IList<MyType>)readObjects(typeof(myType));
但我认为在这种情况下更好地使用#1和泛型参数。
否则你将使用反射。或者一些基类,接口等。这取决于你要解决的具体任务。
P.S。您可以在MSDN上阅读有关generic types的更多信息。