using System; using System.Collections; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace CPF.Windows.Json.Serializer { internal class ExpressionMembers { //- handler; internal static ParameterExpression HandlerArg = Expression.Parameter(typeof(JsonSerializerHandler), "handler"); //- return(label); internal static readonly LabelTarget ReturnLable = Expression.Label(typeof(void)); //- handler.WriteString internal static readonly MemberExpression WriteString = Expression.MakeMemberAccess(HandlerArg, JsonSerializerHandler._WriteString); //- handler.option; internal static readonly MemberExpression JOptionArg = Expression.MakeMemberAccess(HandlerArg, JsonSerializerHandler._Option); //- handler.serializeStacks internal static readonly MemberExpression SerializeStacksArg = Expression.MakeMemberAccess(HandlerArg, JsonSerializerHandler._SerializeStacks); //- handler.option.GlobalKeyFormat(delegate) internal static readonly MemberExpression GlobalKeyFormat = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._GlobalKeyFormat); //- handler.option.GlobalValueFormat(delegate) internal static readonly MemberExpression GlobalValueFormat = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._GlobalValueFormat); //- afterValueFormat(string) internal static readonly ParameterExpression AfterValueFormat = Expression.Variable(typeof(string), "afterValueFormat"); //- isValueFormat(bool) internal static readonly ParameterExpression IsValueFormat = Expression.Variable(typeof(bool), "isValueFormat"); //- handler.option.ignoreKeys(List) internal static readonly MemberExpression IgnoreKeys = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._IgnoreKeys); //- handler.option.ignoreKeys == null internal static readonly BinaryExpression IgnoreKeysIsNull = Expression.Equal(IgnoreKeys, Expression.Constant(null)); //- handler.option.ignoreKeys != null internal static readonly BinaryExpression IgnoreKeysIsNotNull = Expression.NotEqual(IgnoreKeys, Expression.Constant(null)); //- handler.option.ignoreKeys.count() == 0 internal static readonly BinaryExpression IgnoreKeysCountIsZero = Expression.Equal(Expression.MakeMemberAccess(IgnoreKeys, typeof(List).GetProperty("Count")), Expression.Constant(0)); //- handler.option.jsonCharacterRead(Enum) internal static readonly MemberExpression JsonCharacterRead = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._JsonCharacterRead); //- handler.option.isEnumNum(bool) internal static readonly MemberExpression IsEnumNum = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._IsEnumNum); //- handler.option.isIgnoreValueNull(bool) internal static readonly UnaryExpression IgnoreValueNullIsTrue = Expression.IsTrue(Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._IsIgnoreValueNull)); //- handler.option.referenceLoopHandling(Enum) internal static readonly MemberExpression ReferenceLoopHandling = Expression.MakeMemberAccess(JOptionArg, JsonSerializerOption._ReferenceLoopHandling); //- handler.option.referenceLoopHandling != Enum.None internal static readonly BinaryExpression IsReferenceLoopHandlingNotEqualsNone = Expression.NotEqual(ReferenceLoopHandling, Expression.Constant(JsonReferenceHandlingEnum.None)); //- handler.option.referenceLoopHandling == Enum.Remove internal static readonly BinaryExpression IsReferenceLoopHandlingEqualsRemove = Expression.Equal(ReferenceLoopHandling, Expression.Constant(JsonReferenceHandlingEnum.Remove)); //- handler.option.referenceLoopHandling == Enum.Empty internal static readonly BinaryExpression IsReferenceLoopHandlingEqualsEmpty = Expression.Equal(ReferenceLoopHandling, Expression.Constant(JsonReferenceHandlingEnum.Empty)); //- handler.option.referenceLoopHandling == Enum.Null internal static readonly BinaryExpression IsReferenceLoopHandlingEqualsNull = Expression.Equal(ReferenceLoopHandling, Expression.Constant(JsonReferenceHandlingEnum.Null)); //- handler.commaIndexLists internal static readonly MemberExpression ListCommaIndexs = Expression.MakeMemberAccess(HandlerArg, JsonSerializerHandler._CommaIndexLists); //if ( referenceLoopHandling == Enum.Remove ) ==> DeleteComma() internal static readonly ConditionalExpression IsReferenceLoopHandlingIsRemoveDeleteComma = Expression.IfThen( IsReferenceLoopHandlingEqualsRemove, DeleteComma() ); //if ( referenceLoopHandling == Enum.None ) ==> serializeStacks.Pop() internal static readonly ConditionalExpression IsReferenceLoopHandlingIsNoneSerializeStacksArgPop = Expression.IfThen( IsReferenceLoopHandlingNotEqualsNone, Expression.Call(SerializeStacksArg, typeof(Stack).GetMethod("Pop")) ); //call internal static readonly MethodCallExpression WriteLeft = Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Constant("{")); internal static readonly MethodCallExpression WriteRight = Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Constant("}")); internal static readonly MethodCallExpression WriteComma = Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Constant(",")); internal enum RefernceByEmptyType { Array, Dictionary, CustomType } internal static Expression WriteKeyValuePairKey(Type keyType, Expression key) { List calls = new List(); if (keyType == typeof(string) || keyType == typeof(Guid) || keyType == typeof(DateTime)) { calls.Add(GetMethodCall(keyType, key)); calls.Add(Append(":")); } else if (keyType.IsPrimitive) { calls.Add(Append("\"")); calls.Add(Expression.Call(SerializerBootTable.Table.DefaultSameTypes[keyType], key, HandlerArg)); calls.Add(Append("\":")); } else if (keyType.IsEnum)//The default is tostring { calls.Add(Append("\"")); calls.Add(Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Call(key, typeof(Enum).GetMethod("ToString", new Type[0])))); calls.Add(Append("\":")); } return Expression.Block(calls); } internal static Expression IsIgnoreSelfRefernce(ParameterExpression instanceArg, RefernceByEmptyType emptyType) { MethodCallExpression contains = Expression.Call(SerializeStacksArg, typeof(Stack).GetMethod("Contains", new[] { typeof(object) }), Expression.Convert(instanceArg, typeof(object))); MethodCallExpression call; if (emptyType == RefernceByEmptyType.Array) call = RemoveArrayItem(); else if (emptyType == RefernceByEmptyType.Dictionary) call = RemoveDictionaryKey(); else call = RemoveKeyAndAddIndex(); BlockExpression containsBody = Expression.Block( Expression.IfThenElse( IsReferenceLoopHandlingEqualsNull, Append("null"), Expression.IfThenElse( IsReferenceLoopHandlingEqualsEmpty, Append(emptyType == RefernceByEmptyType.Array ? "[]" : "{}"), call) ), Expression.Return(ReturnLable) ); ConditionalExpression ifContainsBlock = Expression.IfThen(contains, containsBody); // handler.serializeStacks.Push(value); MethodCallExpression push = Expression.Call(SerializeStacksArg, typeof(Stack).GetMethod("Push", new[] { typeof(object) }), Expression.Convert(instanceArg, typeof(object))); ConditionalExpression isIgnoreSelfRefernce = Expression.IfThen(IsReferenceLoopHandlingNotEqualsNone, Expression.Block( ifContainsBlock, push )); return isIgnoreSelfRefernce; } internal static MethodCallExpression GetMethodCall(Type type, Expression member) { return Expression.Call(typeof(FormattingProvider<>).MakeGenericType(type).GetMethod("Convert", BindingFlags.NonPublic | BindingFlags.Static), member, HandlerArg); } internal static MethodCallExpression AppendKey(string str) { return Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Constant("\"" + str + "\":")); } internal static MethodCallExpression Append(string str) { return Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, Expression.Constant(str)); } internal static MethodCallExpression Append(Expression strExpression) { return Expression.Call(WriteString, JsonSerializerHandler._WriteStringInvoke, strExpression); } internal static MethodCallExpression RemoveDictionaryKey() { return Expression.Call(RemoveWriterHelper._RemoveDictionaryKey, HandlerArg); } internal static MethodCallExpression RemoveArrayItem() { return Expression.Call(RemoveWriterHelper._RemoveArrayItem, HandlerArg); } internal static MethodCallExpression RemoveKeyAndAddIndex() { return Expression.Call(RemoveWriterHelper._RemoveKeyAndAddIndex, HandlerArg, ListCommaIndexs); } internal static MethodCallExpression RemoveLastComma() { return Expression.Call(RemoveWriterHelper._RemoveLastComma, HandlerArg); } internal static MethodCallExpression DeleteComma() { return Expression.Call(RemoveWriterHelper._DeleteComma, HandlerArg, ListCommaIndexs); } } }