Skip to content

Instantly share code, notes, and snippets.

@doggy8088
Last active May 27, 2024 10:08
Show Gist options
  • Save doggy8088/995a28b2655ec9529414c3df18aaa28e to your computer and use it in GitHub Desktop.
Save doggy8088/995a28b2655ec9529414c3df18aaa28e to your computer and use it in GitHub Desktop.
public class DynamicJsonConverter : JsonConverter<dynamic>
{
public override dynamic Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.True)
{
return true;
}
if (reader.TokenType == JsonTokenType.False)
{
return false;
}
if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt64(out long l))
{
return l;
}
return reader.GetDouble();
}
if (reader.TokenType == JsonTokenType.String)
{
if (reader.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString();
}
if (reader.TokenType == JsonTokenType.StartObject)
{
using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
return ReadObject(documentV.RootElement);
}
if (reader.TokenType == JsonTokenType.StartArray)
{
using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
return ReadList(documentV.RootElement);
}
using JsonDocument document = JsonDocument.ParseValue(ref reader);
return document.RootElement.Clone();
}
private object ReadObject(JsonElement jsonElement)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in jsonElement.EnumerateObject())
{
var k = obj.Name;
var value = ReadValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private object ReadValue(JsonElement jsonElement)
{
object result = null;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Object:
result = ReadObject(jsonElement);
break;
case JsonValueKind.Array:
result = ReadList(jsonElement);
break;
case JsonValueKind.String:
result = jsonElement.GetString();
break;
case JsonValueKind.Number:
if (jsonElement.TryGetDecimal(out decimal d))
{
result = d;
}
else if (jsonElement.TryGetInt64(out long l))
{
result = l;
}
else
{
result = 0;
}
break;
case JsonValueKind.True:
result = true;
break;
case JsonValueKind.False:
result = false;
break;
case JsonValueKind.Undefined:
case JsonValueKind.Null:
result = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
return result;
}
private object ReadList(JsonElement jsonElement)
{
IList<object> list = new List<object>();
foreach (var item in jsonElement.EnumerateArray())
{
list.Add(ReadValue(item));
}
return list.Count == 0 ? null : list;
}
public override void Write(Utf8JsonWriter writer, dynamic value, JsonSerializerOptions options)
{
LINQPad.Extensions.Dump(value, "Write Value");
// https://docs.microsoft.com/en-us/dotnet/api/system.typecode
switch (Type.GetTypeCode((Type)value.GetType()))
{
case TypeCode.Boolean:
writer.WriteBooleanValue(Convert.ToBoolean(value));
break;
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
writer.WriteNumberValue(Convert.ToInt64(value));
break;
case TypeCode.Decimal:
writer.WriteNumberValue(Convert.ToDecimal(value));
break;
case TypeCode.Char:
case TypeCode.Empty:
case TypeCode.String:
writer.WriteStringValue(Convert.ToString(value));
break;
case TypeCode.DateTime:
writer.WriteStringValue(Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss"));
break;
case TypeCode.DBNull:
writer.WriteNullValue();
break;
default:
writer.WriteRawValue(JsonSerializer.Serialize(value, new JsonSerializerOptions() { WriteIndented = true }));
break;
}
}
}
void Main()
{
var serializerOptions = new JsonSerializerOptions
{
Converters = { new DynamicJsonConverter() },
WriteIndented = true
};
var jsonText = File.ReadAllText("sample.json");
dynamic obj = JsonSerializer.Deserialize<dynamic>(jsonText, serializerOptions);
LINQPad.Extensions.Dump(obj, "將 JSON 反序列化成 dynamic 物件");
LINQPad.Extensions.Dump(obj.ppu);
LINQPad.Extensions.Dump(obj.batters.batter[0].id);
LINQPad.Extensions.Dump(obj.batters.batter[0].type);
string json = JsonSerializer.Serialize(obj, serializerOptions);
LINQPad.Extensions.Dump(json, "將 dynamic 物件序列化成 JSON 字串");
}
{
"id": "0001",
"type": "donut",
"name": "Cake",
"enabled": true,
"ppu": 0.55,
"birthday": "2022-06-11 21:42:55",
"nothing": null,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment