从对象转换 List<MyClass> 返回 System.InvalidCastException C# [重复]

Posted

技术标签:

【中文标题】从对象转换 List<MyClass> 返回 System.InvalidCastException C# [重复]【英文标题】:Casting a List<MyClass> back from object returns a System.InvalidCastException C# [duplicate] 【发布时间】:2021-05-10 19:04:52 【问题描述】:

我有一个Dictionary&lt;string,object&gt;,我在其中保存对象以解析到我的插件系统,其中一些对象需要是副本而不是原始对象,因此我使用此 DeepClone 方法:

public static T DeepCloneJSON<T>(this T Obj)
        
            var text = JsonSerializer.Serialize(Obj);
            return JsonSerializer.Deserialize<T>(text);
        

例如,如果我这样做:

var dict = new Dictionary<string,object>()
    "someKey",new List<MyClass>()new MyClass()

var copy = dict["someKey"].DeepCloneJSON();
var cast = (List<MyClass>)copy;

我得到一个 System.InvalidCastException,但如果我使用 MemoryStream DeepCopy 方法,我不会得到这个异常,就像这个:

public static T DeepCloneMemoryStream<T>(this T obj)
        
            using (var ms = new MemoryStream())
            
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            
        

所以,我想知道为什么我使用基于 System.text.json 的 DeepClone 方法得到这个异常,以及是否可以使用 System.text.json 来做到这一点,因为在我的测试中它表现得更快并且比基于 onde 的 MemoryStream 使用更少的内存。

【问题讨论】:

因为您正在调用 DeepCloneJSON&lt;object&gt;,而后者又调用 JsonSerializer.Deserialize&lt;object&gt; 而不是 JsonSerializer.Deserialize&lt;MyClass&gt;。您将需要反射才能使用正确的类型参数调用DeepCloneJSON。虽然您是否应该通过 JSON 进行深度克隆是一个不同的问题...... 【参考方案1】:

您的 DeepCloneMemoryStream 通过反射重新创建确切的类型,即使 T 是对象。

您的 DeepCloneJSON 通过 JSON 字符串往返会丢失类型信息,因此反序列化需要指定确切的类型。在您的情况下,您只是将object 作为T 传递,因此您会返回JsonElement 而不是List&lt;MyClass&gt;

如果您更改拨打电话的方式,以下方法将起作用:

var copy = DeepCloneJSON((List<MyClass>)dict["someKey"]);

或者,更改您的实现,以便根据Obj 的实际类型而不是指定的T 类型进行反序列化 - 这与您的其他实现具有类似的效果,其中T 仅用于强制转换.

public static T DeepCloneJSON<T>(T Obj)

    var text = JsonSerializer.Serialize(Obj);
    return (T)JsonSerializer.Deserialize(text, Obj.GetType());

完全不同的方法

您可以通过选择使用反射发射等技术的各种开源 NuGet 包来避免强制转换异常和序列化和反序列化的开销,以及可能出现的问题(例如私有成员、不可序列化实例等)或表达式树来避免序列化。

如 cmets 中所建议的,一个示例是 FastDeepCloner。还有其他几个提供类似功能。

【讨论】:

以上是关于从对象转换 List<MyClass> 返回 System.InvalidCastException C# [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何将Object转换为字节数组(一个对象为List )

从 List<T> 到数组 T[] 的转换

XmlNodeConverter 只能转换以对象开头的 JSON

如何将 List<Object> 转换为 List<MyClass>

比较 C# 中的两个 List<MyClass>

如何从对象列表中获取不同的列表?