如何检查T是否是泛型方法中的对象列表
本文关键字:泛型方法 对象 列表 是否是 何检查 检查 | 更新日期: 2023-09-27 18:27:36
我正试图用json.NET编写一个从json文件反序列化的通用方法
我希望能够支持反序列化包含对象和对象数组的文件。以下是我目前拥有的两种通用方法的简化版本:
/// <summary> Deserializes object or an array of objects from a list of files. </summary>
public static List<T> Deserialize<T>(List<string> filePathsList)
{
var result = new List<T>();
foreach (var file in filePathsList)
// HOW DO I FIND OUT IF T IS A LIST HERE?
// Resharper says: the given expression is never of the provided type
if (typeof(T) is List<object>)
{
var deserialized = Deserialize<List<T>>(file);
result.AddRange(deserialized);
}
// Resharper says: Suspicious type check: there is not type in the solution
// which is inherited from both 'System.Type' and 'System.Collections.IList'
else if (typeof(T) is IList)
{
// deserializing json file with an array of objects
var deserialized = Deserialize<List<T>>(file);
result.AddRange(deserialized);
}
else
{
// deserializing a single object json file
var deserialized = Deserialize<T>(file);
result.Add(deserialized);
}
return result;
}
/// <summary> Deserializes object or an array of objects from a file. </summary>
public static T Deserialize<T>(string filepath)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(filepath));
}
问题是,在反序列化之前,我需要知道T是对象还是对象列表。如何在泛型方法中检查它?因为重拍给了我警告,而我似乎无法理解这一点。
编辑:我在示例代码中犯了一个错误,正如@Medo42所指出的,它会用List<List<Something>>
调用Deserialize()此外,我根本不应该包含一个涉及json序列化的示例,它应该更通用。问题是关于找出T是否是一个对象列表。
提前感谢您的帮助。
这不是一个完整的答案,但对于注释来说太长了,可能会帮助您更好地理解一些问题。
// Resharper says: the given expression is never of the provided type
if (typeof(T) is List<object>)
雷沙珀是对的。is
操作符检查左边的实例是否属于右边的类型,因此在您的情况下,它会检查typeof(T)
是否是List<object>
的实例。但是,typeof(T)
返回一个Type
实例,表示T
的类型。正确的检查方法(如果你想要确切的类型)是
if (typeof(T) == typeof(List<object>))
但请注意,这仅适用于T
恰好为List<object>
的情况。如果有List<object>
的亚型也是可以的,那么该行将是
if (typeof(List<object>).IsAssignableFrom(typeof(T)))
但你的问题并没有就此结束。您似乎认为List<object>
是所有列表的超类型。事实并非如此,即使我们可以假设我们将只使用列表的List<T>
实现。其原因是List<T>
是不变量。
不变意味着猫的列表不是哺乳动物的列表。如果这看起来违反直觉,那是因为你认为列表是一个固定的集合,你想从中阅读。然而,您也可以向C#列表中添加新项目,如果允许将List<Cat>
视为List<Mammal>
,您最终可能会尝试向该列表中添加大象,这将给仍将该列表引用为List<Cat>
的其他人带来无尽的困惑。
对于类型检查问题的解决方案,我认为drf对dotctor答案的评论是做你认为你想做的事情的最干净的方法:
typeof(T).GetGenericTypeDefinition() == typeof(List<>)
作为最后一句话,以下代码看起来也不稳定:
var deserialized = Deserialize<List<T>>(file);
在弄清楚T
实际上是List<Something>
之后,您可以执行此操作,因此现在您正试图将文件反序列化为List<List<Something>>
,这可能不是您想要的。
你可以很容易地检查
if (typeof(T).Name == "List`1")
{
// T is a generic list
}
正如drf所提到的,一种不依赖内部实现的更好方法是:
if (typeof(T).GetGenericTypeDefinition() == typeof(List<>))
{
// T is a generic list
}
您不需要这个,只需使用LINQ就可以简化代码!!!
/// <summary>
/// Deserializes object or an array of objects from a list of files.
/// </summary>
public static List<T> Deserialize<T>(List<string> filePathsList)
{
return filePathsList
.Select(System.IO.File.ReadAllText)
.Select(JsonConvert.DeserializeObject<T>)
.ToList();
}
@Hamid Pourjam的答案很好,但对非泛型类型抛出了一个异常,所以您也应该检查IsGenericType
。这里有一个helper方法。
public bool IsList(object o)
{
if (o == null) return false;
var type = o.GetType();
return o is IList && type.IsGenericType && type.GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
}
用法:
public class Foo
{
public string Key { get; set; }
}
// #1
var foo = new Foo { Key = "value" };
// #2
var foos = new List<Foo>();
foos.Add(foo);
// #3
var lst = new List<object>();
lst.Add(new { Name = "John" });
IsList(foo); // false
IsList(foos); // true
IsList(lst); // true