Во-первых, отметим, что 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 }));
Demo fiddle # 1 здесь .
При этом, существует несколько опций, указанных в JSON. Net, создает исключение StackOverflowException при использовании [JsonConvert ()] , а также этот ответ до Newtonsoft Json. NET Атрибут JsonConverter сохраняет проблему с ссылками при десериализации для рекурсивного вызова сериализатора для получения десериализации «по умолчанию»:
Если вы не Если вам необходимо предварительно загрузить JSON в иерархию JToken
, вы можете отключить сам преобразователь с помощью элемента потока stati c, а затем вызвать serializer.Deserialize()
рекурсивно.
Если вам нужно предварительно загрузить JSON в иерархию 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 считает массив byte []
, представленный в виде строки Base64, примитивом, поэтому вы можете просто загрузить его в JToken
и использовать явное преобразование JToken (JToken toByte []) * Оператор 1046 * для приведения его к массиву 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 здесь .