in src/DurableTask.AzureStorage/Tracking/TableEntityConverter.cs [142:213]
private static Func<object, TableEntity> CreateTableEntitySerializer(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
Debug.Assert(type.GetCustomAttribute<DataContractAttribute>() != null);
// Indexers use "get_Item" and "set_Item"
MethodInfo setItemMethod = typeof(TableEntity).GetMethod("set_Item", new Type[] { typeof(string), typeof(object) });
MethodInfo serializeMethod = typeof(Utils).GetMethod(nameof(Utils.SerializeToJson), new Type[] { typeof(string) });
ParameterExpression objParam = Expression.Parameter(typeof(object), "obj");
ParameterExpression inputVar = Expression.Variable(type, "input");
ParameterExpression tableVar = Expression.Variable(typeof(TableEntity), "table");
var variables = new List<ParameterExpression> { inputVar, tableVar };
var body = new List<Expression>();
#region if (obj == null) throw new ArgumentNullException(nameof(obj));
body.Add(Expression.IfThen(
Expression.Equal(objParam, Expression.Constant(null, typeof(object))),
Expression.Throw(
Expression.New(
typeof(ArgumentNullException).GetConstructor(new Type[] { typeof(string) }),
Expression.Constant(objParam.Name, typeof(string))))));
#endregion
#region <Type> input = (<Type>)obj;
body.Add(Expression.Assign(inputVar, type != typeof(object) ? Expression.Convert(objParam, type) : objParam));
#endregion
#region TableEntity table = new TableEntity();
body.Add(Expression.Assign(tableVar, Expression.New(typeof(TableEntity))));
#endregion
foreach ((string propertyName, Type memberType, MemberInfo metadata) in EnumerateMembers(type))
{
#region table["<property>"] = (object)/* ... */
Expression valueExpr;
MemberExpression memberExpr = Expression.MakeMemberAccess(inputVar, metadata);
if (memberType.IsEnum)
{
#region table["<property>"] = input.<Member>.ToString("G");
MethodInfo toStringMethod = memberType.GetMethod(nameof(object.ToString), new Type[] { typeof(string) });
valueExpr = Expression.Call(memberExpr, toStringMethod, Expression.Constant("G", typeof(string)));
#endregion
}
else if (IsSupportedType(memberType))
{
#region table["<property>"] = input.<Member>;
valueExpr = memberExpr;
#endregion
}
else
{
// Note: We also serialize nullable enumerations using JSON for backwards compatibility
#region table["<property>"] = Utils.SerializeToJson(input.<Member>);
valueExpr = Expression.Call(null, serializeMethod, memberType != typeof(object) ? Expression.Convert(memberExpr, typeof(object)) : memberExpr);
#endregion
}
body.Add(Expression.Call(tableVar, setItemMethod, Expression.Constant(propertyName, typeof(string)), Expression.Convert(valueExpr, typeof(object))));
#endregion
}
#region return table;
body.Add(tableVar);
#endregion
return Expression.Lambda<Func<object, TableEntity>>(Expression.Block(variables, body), objParam).Compile();
}