我想通过使用类型并保持简单来使我的代码基于约定,但泛型具有自己的复杂性和它自己的学习曲线。
我在列表中有一堆POCO(普通的旧CLR对象),我想在稍后的代码中进行迭代。
var models = new List<Type>();
models.Add(typeof(Person));
models.Add(typeof(Company));
想循环浏览每个列表项:
models.ForEach(m =>
{
var label = m.FullName;
// var data = JsonConvert.DeserializeObject<List<typeof(m)>>(""); // doesn't work
var data = JsonConvert.DeserializeObject<List<m>>(""); // doesn't work either
...
}
问题是反序列化行中的“m”无法正常工作。传递它的最佳方法是什么,即制作'List&lt; m&gt;' '列表&lt; T&gt;'我们可以用吗?
答案 0 :(得分:7)
要使用泛型,你真的需要知道编译时的类型(T
),你不知道 - 你知道运行时 。 (警告:它有可能带有反射,但如果出现过载则不需要使用它,如下所述)
有一个overload of DeserializeObject
需要Type
而不是使用泛型。所以你的代码将是
models.ForEach(m =>
{
var label = m.FullName;
var data = JsonConvert.DeserializeObject("",m);
...
}
但是,正如您在评论中指出的那样,您实际上需要一个List<T>
而不是一个T
。您需要一点点反射,只需创建正确的类型即可转到上面的DeserializeObject
调用。
var tList = typeof(List<>); // Type of open List
models.ForEach(m =>
{
var label = m.FullName;
var tConvert = = tList.MakeGenericType(m);
var data = JsonConvert.DeserializeObject("",tConvert);
...
}
您的问题的答案在上面,但我越看越难以看到您可以<{1>}实际做什么。所有 永远 了解data
是data
。你不能把它投射到任何东西 - 你不知道它是object
的列表还是Person
的列表。
也许这是一个过于人为的例子,你已经习惯了现实生活中的问题。如果不是,我预见到你的下一个问题是如何处理Company
!!
答案 1 :(得分:1)
如果您在编译时不知道类型,可以使用Reflection执行此操作。请考虑以下代码:
models.ForEach(m =>
{
var mi = JsonConvert.GetType()
.GetMethod("DeserializeObject");
var m = mi.MakeGenericMethod(new[] { m });
// you pass [null] for the object because it's a [static] method
// and you don't have to declare [args] if you can express it simply
// but keep in mind that it's simply an object[]
m.Invoke(null, args);
}
答案 2 :(得分:1)
另一个解决方案是使用反射调用泛型方法(如果没有任何重载将类型作为参数)
models.ForEach(m =>
{
MethodInfo method = typeof(JsonConvert).GetMethod("DeserializeObject");
MethodInfo generic = method.MakeGenericMethod(m);
generic.Invoke(null, "");
}