2023-11-21 23:05:03 +08:00

284 lines
10 KiB
C#

using System;
using System.Collections;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace CPF.Windows.Json.Serializer
{
internal class SpecialConditions : DefaultJsonFormatter
{
#region pregenerated metas
internal static MethodInfo _WriteEnum = typeof(SpecialConditions).GetMethod(nameof(WriteEnum), BindingFlags.NonPublic | BindingFlags.Static);
#endregion
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteDynamic(object value, JsonSerializerHandler handler)
{
if (value == null)
{
handler.WriteString("null");
return;
}
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
{
if (handler.SerializeStacks.Contains(value))
{
if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Null)
handler.WriteString("null");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Empty)
handler.WriteString("{}");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Remove)
RemoveWriterHelper.RemoveDictionaryKey(handler);
return;
}
handler.SerializeStacks.Push(value);
}
var t = value.GetType();
handler.WriteString("{");
bool isFirst = true;
foreach (var item in t.GetProperties())
{
if (isFirst)
isFirst = false;
else
handler.WriteString(",");
handler.WriteString("\"");
handler.WriteString(item.Name);
handler.WriteString("\"");
handler.WriteString(":");
#if Net4
SerializerObjectJump.GetThreadSafetyJumpAction(item.PropertyType)(item.GetValue(value, null), handler);
#else
SerializerObjectJump.GetThreadSafetyJumpAction(item.PropertyType)(item.GetValue(value), handler);
#endif
}
handler.WriteString("}");
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void AvoidTypes(object typeVar, JsonSerializerHandler handler)
{
handler.WriteString(typeVar == null ? "null" : "{}");
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteEnum(Enum value, JsonSerializerHandler handler)
{
if (handler.Option.IsEnumNum)
PrimitiveNormal.WriteValue(value.GetHashCode(), handler);
else
{
handler.WriteString("\"");
handler.WriteString(value.ToString());
handler.WriteString("\"");
}
}
#region Array
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteCollection(IEnumerable value, JsonSerializerHandler handler)
{
if (value == null)
{
handler.WriteString("null");
return;
}
var t = value.GetType();
if (t.IsGenericType)
{
var serializerAction = SerializerObjectJump.GetThreadSafetyJumpAction(t);
serializerAction(value, handler);
}
else
{
bool isMultidimensionalArray = false;
Array ary = null;
if (t.IsArray)
{
ary = (Array)value;
if (ary.Rank > 1)
isMultidimensionalArray = true;
}
if (isMultidimensionalArray)
WriteMultidimensionalArray(ary, handler);
else
WriteIEnumerable(value, handler);
}
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteIEnumerable(IEnumerable value, JsonSerializerHandler handler)
{
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
{
if (handler.SerializeStacks.Contains(value))
{
if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Null)
handler.WriteString("null");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Empty)
handler.WriteString("[]");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Remove)
RemoveWriterHelper.RemoveArrayItem(handler);
return;
}
handler.SerializeStacks.Push(value);
}
handler.WriteString("[");
bool isFirst = true;
foreach (var obj in value)
{
if (isFirst)
isFirst = false;
else
handler.WriteString(",");
PrimitiveNormal.WriteValue(obj, handler);
}
handler.WriteString("]");
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
handler.SerializeStacks.Pop();
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteMultidimensionalArray(Array value, JsonSerializerHandler handler)
{
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
{
if (handler.SerializeStacks.Contains(value))
{
if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Null)
handler.WriteString("null");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Empty)
handler.WriteString("[]");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Remove)
RemoveWriterHelper.RemoveArrayItem(handler);
return;
}
handler.SerializeStacks.Push(value);
}
var action = SerializerObjectJump.GetThreadSafetyJumpAction(value.GetType().GetElementType());
handler.WriteString("[");
var enumerator = value.GetEnumerator();
MultidimensionalWrite(enumerator, handler, value, action, value.GetLength(0), 0);
handler.WriteString("]");
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
handler.SerializeStacks.Pop();
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private static void MultidimensionalWrite(IEnumerator enumerator, JsonSerializerHandler handler, Array value, Action<object, JsonSerializerHandler> action, int leng, int level)
{
for (int i = 0; i < leng; i++)
{
if (level != value.Rank - 1)
handler.WriteString("[");
if (level == value.Rank - 1)
{
enumerator.MoveNext();
action(enumerator.Current, handler);
if (i != leng - 1)
handler.WriteString(",");
continue;
}
int localLevel = level;
++localLevel;
MultidimensionalWrite(enumerator, handler, value, action, value.GetLength(localLevel), localLevel);
handler.WriteString("]");
if (i != leng - 1)
handler.WriteString(",");
}
}
#endregion
#region Dictionary
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteDictionary(IDictionary value, JsonSerializerHandler handler)
{
if (value == null)
{
handler.WriteString("null");
return;
}
var t = value.GetType();
if (t.IsGenericType)
{
var serializerAction = SerializerObjectJump.GetThreadSafetyJumpAction(t);
serializerAction(value, handler);
}
else
WriteIDictionary(value, handler);
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal static void WriteIDictionary(IDictionary value, JsonSerializerHandler handler)
{
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
{
if (handler.SerializeStacks.Contains(value))
{
if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Null)
handler.WriteString("null");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Empty)
handler.WriteString("{}");
else if (handler.Option.ReferenceLoopHandling == JsonReferenceHandlingEnum.Remove)
RemoveWriterHelper.RemoveDictionaryKey(handler);
return;
}
handler.SerializeStacks.Push(value);
}
bool isFirst = true;
handler.WriteString("{");
foreach (DictionaryEntry item in value)
{
var keyType = item.Key.GetType();
if (keyType.IsWrongKey())
continue;
if (isFirst)
isFirst = false;
else
handler.WriteString(",");
if (keyType.IsPrimitive || (keyType.IsEnum && handler.Option.IsEnumNum))//string,primitive,enum,guid,datetime
handler.WriteString("\"");
PrimitiveNormal.WriteValue(item.Key, handler);
if (keyType.IsPrimitive || (keyType.IsEnum && handler.Option.IsEnumNum))
handler.WriteString("\"");
handler.WriteString(":");
PrimitiveNormal.WriteValue(item.Value, handler);
}
handler.WriteString("}");
if (handler.Option.ReferenceLoopHandling != JsonReferenceHandlingEnum.None)
handler.SerializeStacks.Pop();
}
#endregion
}
}