internal static void GenerateCopyFieldsExpressions(IEnumerable <FieldInfo> fields, ParameterExpression source, ParameterExpression clone, List <Expression> expressions, ParameterExpression refTrackerParam, ParameterExpression clonedItem) { foreach (var field in fields) { var cloneField = Expression.Field(clone, field); var sourceField = Expression.Field(source, field); if (field.FieldType.IsPrimitive || field.FieldType.IsValueType || (field.FieldType == typeof(string))) { if (field.IsInitOnly) { expressions.Add(Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(field), Expression.Convert(sourceField, typeof(object)), clone)); } else { var from = sourceField; var to = cloneField; expressions.Add(Expression.Assign(to, from)); } } else { var es = new List <Expression>(); es.Add(Expression.Assign(clonedItem, Expression.Call(SerializerMih.PrepareObjectForSerialization(), sourceField))); es.Add(Expression.Assign(clonedItem, CallCopyExpression(clonedItem, refTrackerParam, Expression.Constant(field.FieldType)))); if (IQueryableCloner.IsGenericIQueryableType(field.FieldType)) { Type queryableInterface = IQueryableCloner.GetInterfaceType(field.FieldType, typeof(IQueryable <>)); var genericArgumentType = queryableInterface.GetGenericArguments()[0]; var copy2 = Expression.Convert(clonedItem, field.FieldType); var m = Expression.Call(typeof(Queryable), "AsQueryable", new Type[] { genericArgumentType }, Expression.Convert(copy2, typeof(IEnumerable <>).MakeGenericType(genericArgumentType))); es.Add(Expression.Assign(clonedItem, m)); } if (field.FieldType == typeof(IQueryable)) { es.Add(Expression.Assign(clonedItem, Expression.Call(IQueryableMih.ConvertToNonGenericQueryable(), clonedItem))); } if (field.IsInitOnly) { Func <Expression, Expression> assignExpr = exx => Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(field), Expression.Convert(exx, typeof(object)), clone); var assignNullExpr = Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(field), Expression.Constant(null, typeof(object)), clone); es.Add(clonedItem); var conditionalExpression = Expression.IfThenElse(Expression.NotEqual(sourceField, Expression.Constant(null)), assignExpr(Expression.Block(es)), assignNullExpr); expressions.Add(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(sourceField, cloneField, field.FieldType, refTrackerParam, conditionalExpression, trackedExpression: assignExpr)); // todo refactor this horrible method } else { es.Add(Expression.Assign(cloneField, Expression.Convert(clonedItem, field.FieldType))); var conditionalExpression = Expression.IfThenElse(Expression.Equal(sourceField, Expression.Constant(null)), Expression.Assign(cloneField, Expression.Constant(null, field.FieldType)), Expression.Block(es)); expressions.Add(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(sourceField, cloneField, field.FieldType, refTrackerParam, conditionalExpression)); } } } }
internal static void GenerateReadFieldsExpression(Type type, FieldInfo[] fields, ParameterExpression inputStream, ParameterExpression objTracker, Dictionary <Type, ParameterExpression> temporaryVariables, List <ParameterExpression> variables, ParameterExpression newInstance, List <Expression> notTrackedExpressions, ParameterExpression typeExpr, ParameterExpression typeName, ParameterExpression typeHashCode, ParameterExpression deserializer) { Func <Type, ParameterExpression> getTempVar = t => { ParameterExpression tmpVar; if (!temporaryVariables.TryGetValue(t, out tmpVar)) { tmpVar = Expression.Parameter(t); temporaryVariables.Add(t, tmpVar); variables.Add(tmpVar); } return(tmpVar); }; foreach (var fieldInfo in fields) { var fieldValueExpr = Expression.Field(newInstance, fieldInfo); if (fieldInfo.FieldType == typeof(string)) { if (fieldInfo.IsInitOnly) { var tmpVar = getTempVar(fieldInfo.FieldType); notTrackedExpressions.Add(Expression.Assign(tmpVar, GenerateStringExpression(inputStream, objTracker))); notTrackedExpressions.Add(Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(fieldInfo), Expression.Convert(tmpVar, typeof(object)), newInstance)); } else { var tmpVar = getTempVar(fieldInfo.FieldType); notTrackedExpressions.Add(Expression.Assign(tmpVar, GenerateStringExpression(inputStream, objTracker))); notTrackedExpressions.Add(Expression.Assign(fieldValueExpr, tmpVar)); } } else if (fieldInfo.FieldType.IsPrimitive || fieldInfo.FieldType.IsValueType) { var primitiveReader = GetPrimitiveReader(fieldInfo.FieldType); Expression newValue; if (primitiveReader == null) { var primitiveDeserializer = GetTypeDeserializer(fieldInfo.FieldType); newValue = Expression.Convert(Expression.Invoke(Expression.Constant(primitiveDeserializer), inputStream, objTracker), fieldInfo.FieldType); } else { newValue = primitiveReader(inputStream, objTracker); if (fieldInfo.FieldType == typeof(byte) || fieldInfo.FieldType == typeof(sbyte) || fieldInfo.FieldType == typeof(byte?) || fieldInfo.FieldType == typeof(sbyte?) || IsEnumOrNullableEnum(fieldInfo.FieldType)) { newValue = Expression.Convert(newValue, fieldInfo.FieldType); } } var tmpVar = getTempVar(fieldInfo.FieldType); notTrackedExpressions.Add(Expression.Assign(tmpVar, newValue)); if (fieldInfo.IsInitOnly) { notTrackedExpressions.Add(Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(fieldInfo), Expression.Convert(tmpVar, typeof(object)), newInstance)); } else { notTrackedExpressions.Add(Expression.Assign(fieldValueExpr, tmpVar)); } } else { if (fieldInfo.IsInitOnly) { var tmpVar = getTempVar(typeof(object)); notTrackedExpressions.Add(GetReadClassExpression(inputStream, objTracker, tmpVar, typeExpr, typeName, typeHashCode, deserializer, fieldInfo.FieldType)); notTrackedExpressions.Add(Expression.Call(CopyReadOnlyFieldMethodInfo.GetMethodInfo(), Expression.Constant(fieldInfo), tmpVar, newInstance)); } else { notTrackedExpressions.Add(GetReadClassExpression(inputStream, objTracker, fieldValueExpr, typeExpr, typeName, typeHashCode, deserializer, fieldInfo.FieldType)); } } } }