繁体   English   中英

如何检查T是否是泛型方法中的对象列表

[英]How to check if T is a list of objects in a generic method

我试图用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是对象还是对象列表。 如何检查泛型方法中的内容? 因为resharper给了我警告,我似乎无法解决这个问题。


编辑:我在示例代码中犯了一个错误,因为@Medo42指出,它会用List<List<Something>>调用Deserialize()而且,我不应该包含一个涉及json序列化的例子,它应该更通用了。 问题是找出T是否是对象列表。

在此先感谢您的帮助。

这不是一个完整的答案,但是评论太长了,可能会帮助您更好地理解一些问题。

// Resharper says: the given expression is never of the provided type
if (typeof(T) is List<object>)

而Resharper是对的。 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 这是辅助方法。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM