- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有这样一个类:
public class ComplexClass
{
public ConcurrentBag<SimpleClass> _simpleClassObjects;
}
当我序列化这个类时,它起作用了。但是当我尝试反序列化时
public static ComplexClass LoadComplexClass()
{
ComplexClass persistedComplexClass;
using (var stream = new StreamReader(File.Open(jsonFilePath, FileMode.Open)))
{
persistedComplexClass = (ComplexClass) JsonSerializer.Create().Deserialize(stream, typeof(ComplexClass));
}
return persistedComplexClass;
}
它抛出异常:
An unhandled exception of type 'System.InvalidCastException' occurred in Newtonsoft.Json.dll
Additional information: Unable to cast object of type 'System.Collections.Concurrent.ConcurrentBag`1[LabML.Model.Point]' to type 'System.Collections.Generic.ICollection`1[LabML.Model.Point]'.
此异常的根本原因是 ConcurrentBag<T>
不实现通用 ICollection<T>
, 只有非通用 ICollection
.
如何使用 Json.Net 解决这个问题? (我为此搜索了一段时间,但我发现的只是关于将 ICollection<T>
映射到 ConcurrentCollection
而不是在复杂类中。
最佳答案
更新
从 10.0.3 版开始,Json.NET 声称可以正确序列化 ConcurrentBag<T>
.根据release notes :
原始答案
如您所料,问题在于 ConcurrentBag<T>
工具 ICollection
和 IEnumerable<T>
但不是 ICollection<T>
所以 Json.NET 不知道如何向它添加项目并将其视为只读集合。同时 ConcurrentBag<T>
确实有 parameterized constructor taking an input collection , Json.NET 不会使用该构造函数,因为它在内部也有 [OnSerializing]
和 [OnDeserialized]
回调。当存在这些回调时,Json.NET 将不会使用参数化构造函数,而是抛出异常
Cannot call OnSerializing on an array or readonly list, or list created from a non-default constructor: System.Collections.Concurrent.ConcurrentBag`1[]
因此有必要创建一个custom JsonConverter
对于 ConcurrentBag<T>
:
public class ConcurrentBagConverter : ConcurrentBagConverterBase
{
public override bool CanConvert(Type objectType)
{
return objectType.GetConcurrentBagItemType() != null;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
try
{
var itemType = objectType.GetConcurrentBagItemType();
var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
var genericMethod = method.MakeGenericMethod(new[] { objectType, itemType });
return genericMethod.Invoke(this, new object[] { reader, objectType, itemType, existingValue, serializer });
}
catch (TargetInvocationException ex)
{
// Wrap the TargetInvocationException in a JsonSerializationException
throw new JsonSerializationException("Failed to deserialize " + objectType, ex);
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objectType = value.GetType();
try
{
var itemType = objectType.GetConcurrentBagItemType();
var method = GetType().GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
var genericMethod = method.MakeGenericMethod(new[] { objectType, itemType });
genericMethod.Invoke(this, new object[] { writer, value, serializer });
}
catch (TargetInvocationException ex)
{
// Wrap the TargetInvocationException in a JsonSerializationException
throw new JsonSerializationException("Failed to serialize " + objectType, ex);
}
}
}
public class ConcurrentBagConverter<TItem> : ConcurrentBagConverterBase
{
public override bool CanConvert(Type objectType)
{
return typeof(ConcurrentBagConverter<TItem>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ReadJsonGeneric<ConcurrentBag<TItem>, TItem>(reader, objectType, typeof(TItem), existingValue, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
WriteJsonGeneric<ConcurrentBag<TItem>, TItem>(writer, value, serializer);
}
}
// https://stackoverflow.com/questions/42836648/json-net-deserialize-complex-object-with-concurrent-collection-in-composition
public abstract class ConcurrentBagConverterBase : JsonConverter
{
protected TConcurrentBag ReadJsonGeneric<TConcurrentBag, TItem>(JsonReader reader, Type collectionType, Type itemType, object existingValue, JsonSerializer serializer)
where TConcurrentBag : ConcurrentBag<TItem>
{
if (reader.TokenType == JsonToken.Null)
return null;
if (reader.TokenType != JsonToken.StartArray)
throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));
var collection = existingValue as TConcurrentBag ?? (TConcurrentBag)serializer.ContractResolver.ResolveContract(collectionType).DefaultCreator();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
case JsonToken.EndArray:
return collection;
default:
collection.Add((TItem)serializer.Deserialize(reader, itemType));
break;
}
}
// Should not come here.
throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
}
protected void WriteJsonGeneric<TConcurrentBag, TItem>(JsonWriter writer, object value, JsonSerializer serializer)
where TConcurrentBag : ConcurrentBag<TItem>
{
// Snapshot the bag as an array and serialize the array.
var array = ((TConcurrentBag)value).ToArray();
serializer.Serialize(writer, array);
}
}
internal static class TypeExtensions
{
public static Type GetConcurrentBagItemType(this Type objectType)
{
while (objectType != null)
{
if (objectType.IsGenericType
&& objectType.GetGenericTypeDefinition() == typeof(ConcurrentBag<>))
{
return objectType.GetGenericArguments()[0];
}
objectType = objectType.BaseType;
}
return null;
}
}
public class ConcurrentBagContractResolver : DefaultContractResolver
{
protected override JsonArrayContract CreateArrayContract(Type objectType)
{
var contract = base.CreateArrayContract(objectType);
var concurrentItemType = objectType.GetConcurrentBagItemType();
if (concurrentItemType != null)
{
if (contract.Converter == null)
contract.Converter = (JsonConverter)Activator.CreateInstance(typeof(ConcurrentBagConverter<>).MakeGenericType(new[] { concurrentItemType }));
}
return contract;
}
}
然后,将通用版本应用到您的特定领域,如下所示:
public class ComplexClass
{
[JsonConverter(typeof(ConcurrentBagConverter<SimpleClass>))]
public ConcurrentBag<SimpleClass> _simpleClassObjects;
}
或者,为所有 ConcurrentBag<T>
全局应用通用版本对于任何 T
使用以下设置:
var settings = new JsonSerializerSettings
{
Converters = { new ConcurrentBagConverter() },
};
或者可以使用自定义契约解析器,它的性能可能比使用通用转换器稍微好一些:
var settings = new JsonSerializerSettings
{
ContractResolver = new ConcurrentBagContractResolver(),
};
示例 fiddle .
话虽如此,以上内容仅在 ConcurrentBag<T>
时有效属性或字段是可读/可写的。如果成员是只读的,那么我发现 Json.NET 9.0.1 将跳过反序列化即使存在转换器,因为它推断集合成员和内容都是只读的。 (这可能是 JsonSerializerInternalReader.CalculatePropertyDetails()
中的错误。)
作为一种解决方法,您可以使该属性可私有(private)设置,并用 [JsonProperty]
标记它。 :
public class ComplexClass
{
ConcurrentBag<SimpleClass> m_simpleClassObjects = new ConcurrentBag<SimpleClass>();
[JsonConverter(typeof(ConcurrentBagConverter<SimpleClass>))]
[JsonProperty]
public ConcurrentBag<SimpleClass> _simpleClassObjects { get { return m_simpleClassObjects; } private set { m_simpleClassObjects = value; } }
}
或者使用代理数组属性,从而消除对任何类型转换器的需要:
public class ComplexClass
{
readonly ConcurrentBag<SimpleClass> m_simpleClassObjects = new ConcurrentBag<SimpleClass>();
[JsonIgnore]
public ConcurrentBag<SimpleClass> _simpleClassObjects { get { return m_simpleClassObjects; } }
[JsonProperty("_simpleClassObjects")]
SimpleClass[] _simpleClassObjectsArray
{
get
{
return _simpleClassObjects.ToArray();
}
set
{
if (value == null)
return;
foreach (var item in value)
_simpleClassObjects.Add(item);
}
}
}
关于c# - Json.net反序列化具有并发集合的复杂对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42836648/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!