Skip to content

Instantly share code, notes, and snippets.

@candidodmv
Created September 29, 2019 22:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save candidodmv/12973423c934b93d7ce3dcf7573f0970 to your computer and use it in GitHub Desktop.
Save candidodmv/12973423c934b93d7ce3dcf7573f0970 to your computer and use it in GitHub Desktop.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
public class DictionaryConverter : JsonConverter
{
private IEqualityComparer<string> _comparer = StringComparer.OrdinalIgnoreCase;
private readonly bool _considerEverythingAsString;
public DictionaryConverter()
{
_considerEverythingAsString = false;
}
public DictionaryConverter(bool considerEverythingAsString)
{
_considerEverythingAsString = considerEverythingAsString;
}
public override bool CanWrite => false;
public override bool CanConvert(Type objectType) => objectType == typeof(Dictionary<string, object>);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartObject)
if (!reader.Read())
throw new JsonSerializationException("The root JSON element isn't an dictionary(JavaScript object)");
else
return ReadJson(reader, objectType, existingValue, serializer);
Dictionary<string, object> ret = new Dictionary<string, object>(_comparer);
int depth = 0;
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
if (reader.TokenType != JsonToken.PropertyName)
{
if (!reader.Read())
throw new JsonSerializationException($"Unexpected token! Expected = {nameof(JsonToken.PropertyName)}, Encountered = {reader.TokenType}");
}
else if(reader.TokenType != JsonToken.EndObject)
{
string key = (string)reader.Value;
reader.Read();
if (!IsUnsableType(reader.TokenType))
ret.Add(key, ProccesRecursive(ref reader, ref depth));
reader.Read();
}
}
return ret;
}
protected Func<JsonToken, bool> IsUnsableType = (type) =>
type == JsonToken.StartConstructor || // https://stackoverflow.com/questions/42158409/whats-the-purpose-of-the-newtonsoft-json-jsontoken-startconstructor-token
type == JsonToken.None ||
type == JsonToken.Null ||
type == JsonToken.Undefined ||
type == JsonToken.Comment ||
type == JsonToken.EndConstructor;
protected object ProccesRecursive(ref JsonReader reader, ref int depth)
{
var currentDepth = depth;
switch (reader.TokenType)
{
case JsonToken.StartObject:
Dictionary<string, object> ret = new Dictionary<string, object>(_comparer);
while (reader.TokenType != JsonToken.EndObject)
{
//reader.Read();
if (reader.TokenType != JsonToken.PropertyName)
{
if (!reader.Read())
throw new JsonSerializationException($"Unexpected token! Expected = {nameof(JsonToken.PropertyName)}, Encountered = {reader.TokenType}");
}
else
{
var key = (string)reader.Value;
reader.Read();
if (!IsUnsableType(reader.TokenType))
{
depth++;
ret.Add(key, ProccesRecursive(ref reader, ref depth));
}
reader.Read();
}
}
return ret;
case JsonToken.StartArray:
List<object> arr = new List<object>();
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
if (!IsUnsableType(reader.TokenType))
arr.Add(ProccesRecursive(ref reader, ref depth));
reader.Read();
}
return arr;
case JsonToken.String:
if (!_considerEverythingAsString && Uri.IsWellFormedUriString(reader.Value?.ToString()?.Trim(), UriKind.Absolute) &&
Uri.TryCreate(reader.Value?.ToString()?.Trim(), UriKind.Absolute, out var uri))
return uri;
else if (!_considerEverythingAsString && DateTime.TryParse(reader.Value?.ToString()?.Trim(), out var dt))
return dt;
else
return reader.Value?.ToString().Trim();
case JsonToken.PropertyName:
return reader.Value?.ToString()?.Trim();
case JsonToken.Integer:
case JsonToken.Float:
return _considerEverythingAsString ? reader.Value?.ToString()?.Trim() : Convert.ToDecimal(reader.Value) as object;
case JsonToken.Boolean:
case JsonToken.Date:
case JsonToken.Bytes:
case JsonToken.Raw:
return _considerEverythingAsString ? reader.Value?.ToString()?.Trim() : reader.Value;
case JsonToken.StartConstructor:
case JsonToken.None:
case JsonToken.Null:
case JsonToken.Undefined:
case JsonToken.EndArray:
case JsonToken.Comment:
case JsonToken.EndObject:
case JsonToken.EndConstructor:
default:
return null;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment