/// <summary> /// Generate an expression tree to clone a class /// </summary> /// <param name="variables">Global variables for the expression tree</param> /// <param name="sourceType">Type of the source object</param> /// <param name="source">Source object</param> /// <param name="clone">Clone object</param> /// <param name="refTrackerParam">Reference tracker</param> /// <returns>An expression tree that can clone a class</returns> internal static Expression GenerateClassExpressions(List <ParameterExpression> variables, Type sourceType, ParameterExpression source, ParameterExpression clone, ParameterExpression refTrackerParam) { var cloner = Expression.Parameter(typeof(Func <object, ObjectClonerReferenceTracker, object>), "cloner"); var clonedItem = Expression.Parameter(typeof(object), "clonedItem"); variables.Add(cloner); variables.Add(clonedItem); var ctor = Expression.Call(FormatterServicesMih.GetUninitializedObject(), Expression.Constant(sourceType)); var copyExpressions = new List <Expression>(); var fields = InternalSerializationStuff.GetFields(sourceType); copyExpressions.Add(Expression.Assign(clone, Expression.Convert(ctor, sourceType))); copyExpressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); GenerateCopyFieldsExpressions(fields, source, clone, copyExpressions, refTrackerParam, clonedItem); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(copyExpressions))); }
private static Expression GenerateArrayOfKnownDimension(List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, Type elementType, ParameterExpression refTrackerParam) { var i = Expression.Parameter(typeof(int), "i"); var lengths = Expression.Parameter(typeof(int[]), "lengths"); var rank = sourceType.GetArrayRank(); variables.Add(i); variables.Add(lengths); List <Expression> notTrackedExpressions = new List <Expression>(); notTrackedExpressions.Add(Expression.IfThen(Expression.GreaterThanOrEqual(Expression.Constant(rank), Expression.Constant(255)), Expression.Throw(Expression.New(NotSupportedExceptionMih.ConstructorString(), Expression.Constant("Array with more than 255 dimensions are not supported"))))); notTrackedExpressions.Add(Expression.Assign(lengths, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), Expression.Constant(rank)))); notTrackedExpressions.AddRange(PopulateDimensionalArrayLength(source, i, lengths, rank)); notTrackedExpressions.Add(Expression.Assign(clone, Expression.Convert(Expression.Call(ArrayMih.CreateInstance(), Expression.Constant(elementType), lengths), sourceType))); notTrackedExpressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); notTrackedExpressions.AddRange(GenerateCopyDimensionalArray(source, clone, sourceType, variables, lengths, rank, refTrackerParam)); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(notTrackedExpressions))); }
/// <summary> /// Generate an expression tree that clones ExpandoObject /// </summary> /// <param name="variables">Global variables for the expression tree</param> /// <param name="source">Source object</param> /// <param name="clone">Clone object</param> /// <param name="refTrackerParam">Reference tracker</param> /// <returns>An expression tree that clones ExpandoObject</returns> public static Expression GenerateExpandoObjectExpression(List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, ParameterExpression refTrackerParam) { var enumerableType = typeof(IEnumerable <KeyValuePair <string, object> >); var getEnumeratorMethodInfo = IEnumerableMih.GetEnumerator <string, object>(); var enumeratorMethod = Expression.Call(Expression.Convert(source, enumerableType), getEnumeratorMethodInfo); var dictType = typeof(IDictionary <string, object>); var cloneAsDict = Expression.Parameter(dictType, "cloneDict"); var expressions = new List <Expression>(); variables.Add(cloneAsDict); expressions.Add(Expression.Assign(clone, Expression.New(typeof(ExpandoObject)))); expressions.Add(Expression.Assign(cloneAsDict, Expression.Convert(clone, dictType))); expressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); var loopBodyCargo = new EnumerableLoopBodyCargo(); loopBodyCargo.EnumeratorType = typeof(IEnumerator <KeyValuePair <string, object> >); loopBodyCargo.KvpType = typeof(KeyValuePair <string, object>); expressions.Add(EnumerableLoopHelper.GenerateEnumeratorLoop(variables, CloneKeyValuePair(clone, refTrackerParam), enumeratorMethod, null, loopBodyCargo)); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, typeof(ExpandoObject), refTrackerParam, Expression.Block(expressions))); }
private static Expression CloneDictionaryWithDefaultComparer(Type genericDictionaryType, List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, ParameterExpression refTrackerParam) { var ctor = sourceType.GetConstructor(new Type[0]); if (ctor == null) { throw new MissingConstructorException("Type " + sourceType + " must have a public constructor without parameter."); } var expressions = new List <Expression>(); expressions.Add(Expression.Assign(clone, Expression.New(ctor))); expressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); CopyFieldsAndValues(genericDictionaryType, source, clone, sourceType, refTrackerParam, expressions, variables); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(expressions))); }
private static Expression GenerateJaggedArray(List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, ParameterExpression refTrackerParam) { var elementType = sourceType.GetElementType(); var item = Expression.Parameter(elementType, "item"); var clonedItem = Expression.Parameter(elementType, "item"); var typeExpr = Expression.Parameter(typeof(Type), "typeExpr"); var i = Expression.Parameter(typeof(int), "i"); var length = Expression.Parameter(typeof(int), "length"); variables.Add(typeExpr); variables.Add(clonedItem); variables.Add(item); variables.Add(length); variables.Add(i); var notTrackedExpressions = new List <Expression>(); notTrackedExpressions.Add(Expression.Assign(length, Expression.Property(source, "Length"))); notTrackedExpressions.Add(Expression.Assign(i, Expression.Constant(0))); notTrackedExpressions.Add(Expression.Assign(clone, Expression.Convert(Expression.New(sourceType.GetConstructor(new[] { typeof(int) }), length), sourceType))); notTrackedExpressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); Debug.Assert(!elementType.IsPrimitive && !elementType.IsValueType && elementType != typeof(string), "Element type cannot be a primitive type"); var loopExpressions = new List <Expression>(); loopExpressions.Add(Expression.Assign(item, Expression.Convert(Expression.Call(source, ArrayMih.GetValue(), i), elementType))); loopExpressions.Add(ClassCloner.GetCloneClassTypeExpression(refTrackerParam, item, clonedItem, elementType)); loopExpressions.Add(Expression.Call(clone, ArrayMih.SetValue(), Expression.Convert(clonedItem, typeof(object)), i)); loopExpressions.Add(Expression.Assign(i, Expression.Add(i, Expression.Constant(1)))); var cond = Expression.LessThan(i, length); var loopBody = Expression.Block(loopExpressions); var breakLabel = Expression.Label("breakLabel"); var loop = Expression.Loop(Expression.IfThenElse(cond, loopBody, Expression.Break(breakLabel)), breakLabel); notTrackedExpressions.Add(loop); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(notTrackedExpressions))); }
/// <summary> /// Generate an expression tree for arrays /// </summary> /// <param name="variables">Global variables for the expression tree</param> /// <param name="source">Source object</param> /// <param name="clone">Clone object</param> /// <param name="sourceType">Type of the source object</param> /// <param name="refTrackerParam">Reference tracker</param> /// <returns>Expression tree to clone arrays</returns> public static Expression GenerateArrayExpression(List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, ParameterExpression refTrackerParam) { var elementType = sourceType.GetElementType(); if (elementType.IsPrimitive || elementType.IsValueType || (elementType == typeof(string))) { return(Expression.Block(Expression.Assign(clone, Expression.Convert(Expression.Call(Expression.Convert(source, typeof(Array)), ArrayMih.Clone()), sourceType)), Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone))); } if (elementType.IsArray) { return(GenerateJaggedArray(variables, source, clone, sourceType, refTrackerParam)); } else { return(GenerateArrayOfKnownDimension(variables, source, clone, sourceType, elementType, refTrackerParam)); } }
private static Expression CloneDictionaryWithCustomComparer(Type genericDictionaryType, ConstructorInfo comparerConstructor, List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, ParameterExpression refTrackerParam) { if (comparerConstructor == null) { throw new MissingConstructorException("Type " + sourceType + " must have a public constructor that takes an IEqualityComparer<> parameter."); } var expressions = new List <Expression>(); var sourceComparer = Expression.Property(source, nameof(Dictionary <int, int> .Comparer)); var comparerType = typeof(IEqualityComparer <>).MakeGenericType(genericDictionaryType.GetGenericArguments()[0]); var clonedComparer = ClassCloner.CallCopyExpression(sourceComparer, refTrackerParam, Expression.Constant(comparerType)); expressions.Add(Expression.Assign(clone, Expression.New(comparerConstructor, Expression.Convert(clonedComparer, comparerType)))); expressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); CopyFieldsAndValues(genericDictionaryType, source, clone, sourceType, refTrackerParam, expressions, variables); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(expressions))); }
/// <summary> /// Generates an expression tree to clone an ISerializable /// </summary> /// <param name="variables">Global variables for the expression tree</param> /// <param name="source">Source object</param> /// <param name="clone">Clone object</param> /// <param name="sourceType">Type of the source object</param> /// <param name="refTrackerParam">Reference tracker</param> /// <returns>An expression tree to clone an ISerializable</returns> public static Expression GenerateISerializableExpression(List <ParameterExpression> variables, ParameterExpression source, ParameterExpression clone, Type sourceType, ParameterExpression refTrackerParam) { var serializationConstructor = ISerializableSerializer.GetSerializationConstructor(sourceType); if (serializationConstructor == null) { throw new MissingConstructorException("Cannot serialize type " + sourceType + " because it does not have the required constructor for ISerializable. If you inherits from a class that implements ISerializable you have to expose the serialization constructor."); } var getEnumeratorMethodInfo = SerializationInfoMih.GetEnumerator(); var siSource = Expression.Parameter(typeof(SerializationInfo), "siSource"); var fc = Expression.Parameter(typeof(FormatterConverter), "fc"); var context = Expression.Parameter(typeof(StreamingContext), "context"); var iserSource = Expression.Parameter(typeof(ISerializable), "iserSource"); var siClone = Expression.Parameter(typeof(SerializationInfo), "siClone"); var cloner = Expression.Parameter(typeof(Func <object, ObjectClonerReferenceTracker, object>), "cloner"); var clonedItem = Expression.Parameter(typeof(object), "clonedItem"); variables.Add(fc); variables.Add(context); variables.Add(siSource); variables.Add(iserSource); variables.Add(siClone); variables.Add(cloner); variables.Add(clonedItem); var enumeratorMethod = Expression.Call(siSource, getEnumeratorMethodInfo); var loopBodyCargo = new EnumerableLoopBodyCargo(); loopBodyCargo.EnumeratorType = typeof(SerializationInfoEnumerator); loopBodyCargo.KvpType = typeof(SerializationEntry); var expressions = new List <Expression>(); expressions.Add(Expression.Assign(fc, Expression.New(typeof(FormatterConverter)))); expressions.Add(Expression.Assign(context, Expression.New(StreamingContextMih.Constructor(), Expression.Constant(StreamingContextStates.All)))); expressions.Add(Expression.Assign(siSource, Expression.New(SerializationInfoMih.Constructor(), Expression.Constant(sourceType), fc))); expressions.Add(Expression.Assign(iserSource, Expression.Convert(source, typeof(ISerializable)))); expressions.Add(Expression.Assign(siClone, Expression.New(SerializationInfoMih.Constructor(), Expression.Constant(sourceType), fc))); expressions.AddRange(SerializationCallbacksHelper.GenerateOnSerializingAttributeExpression(sourceType, source, context)); expressions.Add(Expression.Call(iserSource, ISerializableMih.GetObjectData(), siSource, context)); expressions.AddRange(SerializationCallbacksHelper.GenerateOnSerializedAttributeExpression(sourceType, source, context)); expressions.Add(Expression.IfThen(Expression.IsTrue(Expression.Property(siSource, "IsFullTypeNameSetExplicit")), Expression.Throw(Expression.New(InvalidOperationExceptionMih.Constructor(), Expression.Constant("Changing the full type name for an ISerializable is not supported"))))); expressions.Add(Expression.IfThen(Expression.IsTrue(Expression.Property(siSource, "IsAssemblyNameSetExplicit")), Expression.Throw(Expression.New(InvalidOperationExceptionMih.Constructor(), Expression.Constant("Changing the assembly name for an ISerializable is not supported"))))); expressions.Add(EnumerableLoopHelper.GenerateEnumeratorLoop(variables, GetLoopBodyCargo(siClone, clonedItem, refTrackerParam), enumeratorMethod, null, loopBodyCargo)); expressions.Add(Expression.Assign(clone, Expression.New(serializationConstructor, siClone, context))); expressions.Add(Expression.Call(refTrackerParam, ObjectClonerReferenceTrackerMih.Track(), source, clone)); expressions.AddRange(SerializationCallbacksHelper.GenerateOnDeserializedAttributeExpression(sourceType, clone, context)); expressions.Add(SerializationCallbacksHelper.GenerateCallIDeserializationExpression(sourceType, clone)); return(ObjectCloner.GenerateNullTrackedOrUntrackedExpression(source, clone, sourceType, refTrackerParam, Expression.Block(expressions))); }