从对象转换 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<string,object>
,我在其中保存对象以解析到我的插件系统,其中一些对象需要是副本而不是原始对象,因此我使用此 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<object>
,而后者又调用 JsonSerializer.Deserialize<object>
而不是 JsonSerializer.Deserialize<MyClass>
。您将需要反射才能使用正确的类型参数调用DeepCloneJSON
。虽然您是否应该通过 JSON 进行深度克隆是一个不同的问题......
【参考方案1】:
您的 DeepCloneMemoryStream
通过反射重新创建确切的类型,即使 T
是对象。
您的 DeepCloneJSON
通过 JSON 字符串往返会丢失类型信息,因此反序列化需要指定确切的类型。在您的情况下,您只是将object
作为T
传递,因此您会返回JsonElement
而不是List<MyClass>
。
如果您更改拨打电话的方式,以下方法将起作用:
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# [重复]的主要内容,如果未能解决你的问题,请参考以下文章
XmlNodeConverter 只能转换以对象开头的 JSON