public static TableEntity Serialize()

in src/DurableTask.AzureStorage/Tracking/TableEntityConverter.cs [37:140]


        public static TableEntity Serialize(object obj) =>
            SerializerCache.GetOrAdd(obj?.GetType(), t => CreateTableEntitySerializer(t)).Invoke(obj);

        public static object Deserialize(TableEntity entity, Type type) =>
            DeserializeCache.GetOrAdd(type, t => CreateTableEntityDeserializer(t)).Invoke(entity);

        private static Func<TableEntity, object> CreateTableEntityDeserializer(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            Debug.Assert(type.GetCustomAttribute<DataContractAttribute>() != null);

            MethodInfo getStringMethod = typeof(TableEntity).GetMethod(nameof(TableEntity.GetString), new Type[] { typeof(string) });
            MethodInfo parseMethod = typeof(Enum).GetMethod(nameof(Enum.Parse), new Type[] { typeof(Type), typeof(string) });
            MethodInfo deserializeMethod = typeof(Utils).GetMethod(nameof(Utils.DeserializeFromJson), new Type[] { typeof(string) });

            ParameterExpression tableParam = Expression.Variable(typeof(TableEntity), "table");
            ParameterExpression outputVar = Expression.Parameter(type, "output");
            var variables = new List<ParameterExpression> { outputVar };
            var body = new List<Expression>();

            #region if (table == null) throw new ArgumentNullException(nameof(table));
            body.Add(Expression.IfThen(
                Expression.Equal(tableParam, Expression.Constant(null, typeof(TableEntity))),
                Expression.Throw(
                    Expression.New(
                        typeof(ArgumentNullException).GetConstructor(new Type[] { typeof(string) }),
                        Expression.Constant(tableParam.Name, typeof(string))))));
            #endregion

            #region <Type> output = (<Type>)FormatterServices.GetUninitializedObject(typeof(<Type>));
            MethodInfo getUninitializedObjectMethod = typeof(FormatterServices).GetMethod(nameof(FormatterServices.GetUninitializedObject), new Type[] { typeof(Type) });
            body.Add(Expression.Assign(
                outputVar,
                Expression.Convert(
                    Expression.Call(null, getUninitializedObjectMethod, Expression.Constant(type, typeof(Type))),
                    type)));
            #endregion

            foreach ((string propertyName, Type memberType, MemberInfo metadata) in EnumerateMembers(type))
            {
                #region output.<Member> = /* ... */
                Expression valueExpr;
                if (memberType.IsEnum)
                {
                    #region string <Member>Variable = table.GetString("<property>");
                    ParameterExpression enumStringVar = Expression.Parameter(typeof(string), propertyName + "Variable");
                    variables.Add(enumStringVar);

                    body.Add(Expression.Assign(enumStringVar, Expression.Call(tableParam, getStringMethod, Expression.Constant(propertyName, typeof(string)))));
                    #endregion

                    #region output.<Member> = <Member>Variable == null ? default(<MemberType>) : (<MemberType>)Enum.Parse(typeof(<MemberType>), <Member>Variable);
                    valueExpr = Expression.Condition(
                        Expression.Equal(enumStringVar, Expression.Constant(null, typeof(string))),
                        Expression.Default(memberType),
                        Expression.Convert(Expression.Call(null, parseMethod, Expression.Constant(memberType, typeof(Type)), enumStringVar), memberType));
                    #endregion
                }
                else if(IsSupportedType(memberType))
                {
                    #region output.<Member> = table.Get<MemberType>("<property>");
                    MethodInfo accessorMethod = GetEntityAccessor(memberType);
                    valueExpr = Expression.Call(tableParam, accessorMethod, Expression.Constant(propertyName, typeof(string)));
                    #endregion

                    if (memberType.IsValueType && !memberType.IsGenericType) // Cannot be null
                    {
                        #region output.<Member> = table.Get<MemberType>("<property>").GetValueOrDefault();
                        valueExpr = Expression.Call(valueExpr, typeof(Nullable<>).MakeGenericType(memberType).GetMethod(nameof(Nullable<int>.GetValueOrDefault), Type.EmptyTypes));
                        #endregion
                    }
                }
                else
                {
                    // Note: We also deserialize nullable enumerations using JSON for backwards compatibility
                    #region string <Member>Variable = table.GetString("<property>");
                    ParameterExpression jsonVariable = Expression.Parameter(typeof(string), propertyName + "Variable");
                    variables.Add(jsonVariable);

                    body.Add(Expression.Assign(jsonVariable, Expression.Call(tableParam, getStringMethod, Expression.Constant(propertyName, typeof(string)))));
                    #endregion

                    #region output.<Member> = = <Member>Variable == null ? default(<MemberType>) : Utils.DeserializeFromJson<<MemberType>>(<Member>Variable);
                    valueExpr = Expression.Condition(
                        Expression.Equal(jsonVariable, Expression.Constant(null, typeof(string))),
                        Expression.Default(memberType),
                        Expression.Call(null, deserializeMethod.MakeGenericMethod(memberType), jsonVariable));
                    #endregion
                }

                body.Add(Expression.Assign(Expression.MakeMemberAccess(outputVar, metadata), valueExpr));
                #endregion
            }

            #region return (object)output;
            body.Add(type != typeof(object) ? Expression.Convert(outputVar, type) : outputVar);
            #endregion

            return Expression.Lambda<Func<TableEntity, object>>(Expression.Block(variables, body), tableParam).Compile();
        }