Beispiel #1
0
        /// <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)));
        }
Beispiel #2
0
        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)));
        }
Beispiel #3
0
        /// <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)));
        }
Beispiel #4
0
        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)));
        }
Beispiel #5
0
        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)));
        }
Beispiel #6
0
        /// <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));
            }
        }
Beispiel #7
0
        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)));
        }
Beispiel #8
0
        /// <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)));
        }