我正试图实现这里所描述的大致的目标:
递归调用JsonSerializer中的JsonConverter
简而言之,要检查正在反序列化的值,要么在我自己的代码中使用它,要么把它交给默认的反序列化器。
该示例使用巧妙的技巧来避免递归调用相同的自定义代码:
...
else if (reader.TokenType == JsonToken.StartObject)
// Use DummyDictionary to fool JsonSerializer into not using this converter recursively
dictionary = serializer.Deserialize<DummyDictionary>(reader);
else
dictionary = new Dictionary<TKey, TValue>();
return dictionary;
/// <summary>
/// Dummy to fool JsonSerializer into not using this converter recursively
/// </summary>
private class DummyDictionary : Dictionary<TKey, TValue> { }当DummyDictionary寻找新的反序列化器时,Json.Net类充当控制流的代理。
我需要在byte[]而不是字典中实现同样的目标。如果是字符串,我想将它传递给默认的处理程序。如果一个整数数组,我会处理好自己。
不幸的是,我无法实现
private class DummyByteArray : byte[] { }因为字节是一个值类型,不是一个可继承的接口。
如何在不将对象中的每个byte[]实例更改为SomeNoddyByteProxy的情况下实现所需的控件?
发布于 2020-02-17 03:48:39
首先,顺便提一下,我注意到Json.NET支持将整数数组和Base64字符串反序列化为byte []数组。也就是说,下面的单元测试断言都是只工作
Assert.IsTrue(JsonConvert.DeserializeObject<byte []>("[1, 2]")
.SequenceEqual(new [] { (byte)1, (byte)2 }));
Assert.IsTrue(JsonConvert.DeserializeObject<byte []>("\"AQI=\"")
.SequenceEqual(new [] { (byte)1, (byte)2 }));演示小提琴#1 这里。
尽管如此,https://stackoverflow.com/q/29719509/3744182和这个答案给https://stackoverflow.com/q/54550629/3744182提供了几个选项,用于递归调用序列化程序以获得“默认”反序列化:
JToken层次结构中,则可以让转换器使用线程静态成员禁用自身,然后递归调用serializer.Deserialize()。JToken层次结构中,则可以将该层次结构嵌入到父容器中,并使用容器成员上的虚拟转换器取代和禁用转换器。使用选项1的示例转换器可能如下所示:
public sealed class ByteConverter : JsonConverter<byte[]>
{
[ThreadStatic]
static bool disabled;
// Disables the converter in a thread-safe manner.
bool Disabled { get { return disabled; } set { disabled = value; } }
public override bool CanRead { get { return !Disabled; } }
public override byte[] ReadJson(JsonReader reader, Type objectType, byte[] existingValue, bool hasExistingValue, JsonSerializer serializer)
{
switch (reader.MoveToContentAndAssert().TokenType) // Skip past comments
{
case JsonToken.Null:
return null;
case JsonToken.StartArray:
// Your custom logic here, e.g.:
return serializer.Deserialize<List<byte>>(reader).ToArray();
default:
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val))
return serializer.Deserialize<byte []>(reader);
}
}
// Remainder omitted
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, byte[] value, JsonSerializer serializer) => throw new NotImplementedException();
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
}
public static partial class JsonExtensions
{
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}演示小提琴#2 这里。
然而,在您的情况下,事情更简单。Json.NET将表示为Base64字符串的byte []数组视为原语,因此您可以简单地将其加载到JToken中,并使用JToken显式转换(JToken toByte[])运算符将其转换为byte[]数组,如下所示:
public class ByteConverter : JsonConverter<byte[]>
{
public override byte[] ReadJson(JsonReader reader, Type objectType, byte[] existingValue, bool hasExistingValue, JsonSerializer serializer)
{
switch (reader.MoveToContentAndAssert().TokenType) // Skip past comments
{
case JsonToken.Null:
return null;
case JsonToken.StartArray:
// Your custom logic here, e.g.:
return serializer.Deserialize<List<byte>>(reader).ToArray();
default:
return (byte[])JToken.Load(reader);
}
}
// Remainder omitted这完全避免了序列化程序的使用。演示小提琴#3 这里。
https://stackoverflow.com/questions/60254867
复制相似问题