private static IEnumerable <Expression> ReadDimensionalArrayLength(ParameterExpression inputStream, ParameterExpression objTracker, Expression lengths, Expression i, Expression numberOfDimensions) { var loopExpressions = new List <Expression>(); var expressions = new List <Expression>(); expressions.Add(Expression.Assign(i, Expression.Constant(0))); expressions.Add(Expression.Assign(numberOfDimensions, Expression.Convert(PrimitiveHelpers.ReadByte(inputStream, objTracker), typeof(int)))); expressions.Add(Expression.Assign(lengths, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), numberOfDimensions))); loopExpressions.Add(Expression.Assign(Expression.ArrayAccess(lengths, i), PrimitiveHelpers.ReadInt32(inputStream, objTracker))); loopExpressions.Add(Expression.Assign(i, Expression.Add(i, Expression.Constant(1)))); var loopBody = Expression.Block(loopExpressions); var breakLabel = Expression.Label("breakLabel"); var cond = Expression.LessThan(i, numberOfDimensions); var loop = Expression.Loop(Expression.IfThenElse(cond, loopBody, Expression.Break(breakLabel)), breakLabel); expressions.Add(loop); return(expressions); }
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 to handle array serialization /// </summary> /// <param name="type">Type of the array</param> /// <param name="elementType">Type of the elements contained inside the array</param> /// <param name="outputStream">Stream that is written to</param> /// <param name="objToSerialize">Object to serialize</param> /// <param name="objTracking">Reference tracker</param> /// <returns>An expression tree to handle array serialization</returns> internal static Expression GenerateArrayOfKnownDimension(Type type, Type elementType, ParameterExpression outputStream, ParameterExpression objToSerialize, ParameterExpression objTracking) { List <Expression> notTrackedExpressions = new List <Expression>(); List <ParameterExpression> variables = new List <ParameterExpression>(); var i = Expression.Parameter(typeof(int), "i"); var lengths = Expression.Parameter(typeof(int[]), "lengths"); var trackedObjectPosition = Expression.Parameter(typeof(int?), "trackedObjectPosition"); var arr = Expression.Parameter(type, "arr"); var rank = type.GetArrayRank(); variables.Add(trackedObjectPosition); variables.Add(i); variables.Add(lengths); variables.Add(arr); notTrackedExpressions.Add(Expression.Call(objTracking, SerializerObjectTrackerMih.TrackObject(), objToSerialize)); notTrackedExpressions.Add(Expression.Assign(arr, Expression.Convert(objToSerialize, type))); notTrackedExpressions.Add(Expression.Assign(lengths, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), Expression.Constant(rank)))); notTrackedExpressions.Add(Expression.Assign(i, Expression.Constant(0))); 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.AddRange(WriteDimensionalArrayLength(outputStream, objTracking, i, arr, lengths, rank)); notTrackedExpressions.AddRange(WriteDimensionalArray(elementType, variables, outputStream, arr, rank, lengths, objTracking)); return(Serializer.GenerateNullTrackedOrUntrackedExpression(type, outputStream, objToSerialize, objTracking, notTrackedExpressions, variables)); }
private static IEnumerable <Expression> ReadDimensionalArray(Type type, Type elementType, ParameterExpression newInstance, List <ParameterExpression> variables, ParameterExpression inputStream, ParameterExpression lengths, ParameterExpression objTracker, int rank) { var typeName = Expression.Parameter(typeof(string), "typeName"); var typeExpr = Expression.Parameter(typeof(TypeWithHashCode), "type"); var indices = Expression.Parameter(typeof(int[]), "indices"); var tmpValue = Expression.Parameter(elementType, "tmpValue"); var deserializer = Expression.Parameter(typeof(Func <Stream, DeserializerObjectTracker, object>), "deserializer"); var typeHashCode = Expression.Parameter(typeof(int), "typeHashCode"); variables.Add(deserializer); variables.Add(typeName); variables.Add(typeExpr); variables.Add(tmpValue); variables.Add(typeHashCode); var expressions = new List <Expression>(); expressions.Add(Expression.Assign(newInstance, Expression.Convert(Expression.Call(ArrayMih.CreateInstance(), Expression.Constant(elementType), lengths), type))); if (type.IsClass) { expressions.Add(Expression.Call(objTracker, DeserializerObjectTrackerMih.TrackedObject(), newInstance)); } if (rank > 1) { variables.Add(indices); expressions.Add(Expression.Assign(indices, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), Expression.Property(lengths, "Length")))); } Expression innerExpression; if (elementType == typeof(string)) { innerExpression = Expression.Assign(tmpValue, Deserializer.GenerateStringExpression(inputStream, objTracker)); } else if (elementType.IsPrimitive || elementType.IsValueType) { var primitiveReader = Deserializer.GetPrimitiveReader(elementType); if (primitiveReader == null) { var primitiveDeserializer = Deserializer.GetTypeDeserializer(elementType); innerExpression = Expression.Assign(tmpValue, Expression.Convert(Expression.Invoke(Expression.Constant(primitiveDeserializer), inputStream, objTracker), elementType)); } else { if (elementType == typeof(byte) || elementType == typeof(sbyte) || elementType == typeof(byte?) || elementType == typeof(sbyte?) || Deserializer.IsEnumOrNullableEnum(elementType)) { innerExpression = Expression.Assign(tmpValue, Expression.Convert(primitiveReader(inputStream, objTracker), elementType)); } else { innerExpression = Expression.Assign(tmpValue, primitiveReader(inputStream, objTracker)); } } } else { innerExpression = Deserializer.GetReadClassExpression(inputStream, objTracker, tmpValue, typeExpr, typeName, typeHashCode, deserializer, elementType); } Func <int, Expression, Expression> readArrayLoop = (loopRank, innerExpr) => { var loopRankIndex = Expression.Parameter(typeof(int), "loopRankIndex" + loopRank); variables.Add(loopRankIndex); var loopExpressions = new List <Expression>(); if (rank == 1) { loopExpressions.Add(innerExpr); loopExpressions.Add(Expression.Assign(Expression.ArrayAccess(newInstance, loopRankIndex), tmpValue)); } else { loopExpressions.Add(Expression.Assign(Expression.ArrayAccess(indices, Expression.Constant(loopRank)), loopRankIndex)); loopExpressions.Add(innerExpr); loopExpressions.Add(Expression.Call(newInstance, ArrayMih.SetValueRank(), Expression.Convert(tmpValue, typeof(object)), indices)); } loopExpressions.Add(Expression.Assign(loopRankIndex, Expression.Add(loopRankIndex, Expression.Constant(1)))); var cond = Expression.LessThan(loopRankIndex, Expression.ArrayIndex(lengths, Expression.Constant(loopRank))); var loopBody = Expression.Block(loopExpressions); var breakLabel = Expression.Label("breakLabel" + loopRank); var loop = Expression.Loop(Expression.IfThenElse(cond, loopBody, Expression.Break(breakLabel)), breakLabel); return(Expression.Block(Expression.Assign(loopRankIndex, Expression.Constant(0)), loop)); }; for (int r = rank - 1; r >= 0; r--) { innerExpression = readArrayLoop(r, innerExpression); } expressions.Add(innerExpression); return(expressions); }
private static IEnumerable <Expression> GenerateCopyDimensionalArray(ParameterExpression sourceArray, ParameterExpression cloneArray, Type sourceType, List <ParameterExpression> variables, ParameterExpression lengths, int rank, ParameterExpression refTrackerParam) { var elementType = sourceType.GetElementType(); var item = Expression.Parameter(elementType, "item"); var clonedItem = Expression.Parameter(elementType, "clonedItem"); var typeExpr = Expression.Parameter(typeof(Type), "typeExpr"); var indices = Expression.Parameter(typeof(int[]), "indices"); variables.Add(typeExpr); variables.Add(item); variables.Add(indices); variables.Add(clonedItem); var expressions = new List <Expression>(); expressions.Add(Expression.Assign(indices, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), Expression.Constant(rank)))); Debug.Assert(!(elementType.IsPrimitive || elementType.IsValueType || elementType == typeof(string)), "This method is not made to handle primitive types"); Expression innerExpression = Expression.Block(ClassCloner.GetCloneClassTypeExpression(refTrackerParam, item, clonedItem, elementType), Expression.Call(cloneArray, ArrayMih.SetValueRank(), Expression.Convert(clonedItem, typeof(object)), indices)); Func <int, Expression, Expression> makeArrayLoop = (loopRank, innerExpr) => { var loopRankIndex = Expression.Parameter(typeof(int), "loopRankIndex" + loopRank); variables.Add(loopRankIndex); var loopExpressions = new List <Expression>(); loopExpressions.Add(Expression.Assign(Expression.ArrayAccess(indices, Expression.Constant(loopRank)), loopRankIndex)); loopExpressions.Add(Expression.Assign(item, Expression.Convert(Expression.Call(sourceArray, ArrayMih.GetValueRank(), indices), elementType))); loopExpressions.Add(innerExpr); loopExpressions.Add(Expression.Assign(loopRankIndex, Expression.Add(loopRankIndex, Expression.Constant(1)))); var cond = Expression.LessThan(loopRankIndex, Expression.ArrayIndex(lengths, Expression.Constant(loopRank))); var loopBody = Expression.Block(loopExpressions); var breakLabel = Expression.Label("breakLabel" + loopRank); var loop = Expression.Loop(Expression.IfThenElse(cond, loopBody, Expression.Break(breakLabel)), breakLabel); return(Expression.Block(Expression.Assign(loopRankIndex, Expression.Constant(0)), loop)); }; for (int r = rank - 1; r >= 0; r--) { innerExpression = makeArrayLoop(r, innerExpression); } expressions.Add(innerExpression); return(expressions); }
private static IEnumerable <Expression> WriteDimensionalArray(Type elementType, List <ParameterExpression> variables, ParameterExpression outputStream, ParameterExpression arr, int rank, ParameterExpression lengths, ParameterExpression objTracking) { var item = Expression.Parameter(elementType, "item"); var serializer = Expression.Parameter(typeof(Action <Stream, object, SerializerObjectTracker>), "serializer"); var itemAsObj = Expression.Parameter(typeof(object), "itemAsObj"); var typeExpr = Expression.Parameter(typeof(Type), "typeExpr"); var indices = Expression.Parameter(typeof(int[]), "indices"); variables.Add(typeExpr); variables.Add(itemAsObj); variables.Add(serializer); variables.Add(item); var expressions = new List <Expression>(); if (rank != 1) { variables.Add(indices); expressions.Add(Expression.Assign(indices, Expression.Call(CreateArrayMethodInfo.GetCreateArrayMethodInfo(typeof(int)), Expression.Constant(rank)))); } Expression innerExpression; if (elementType == typeof(string)) { innerExpression = Serializer.GenerateStringExpression(outputStream, item, objTracking); } else if (elementType.IsPrimitive || elementType.IsValueType) { var primitiveWriter = Serializer.GetPrimitiveWriter(elementType); if (primitiveWriter == null) { var primitiveSerializer = Serializer.GetTypeSerializer(elementType); innerExpression = Expression.Invoke(Expression.Constant(primitiveSerializer), outputStream, item, objTracking); } else { innerExpression = primitiveWriter(outputStream, item, objTracking); } } else { innerExpression = Serializer.GetWriteClassTypeExpression(outputStream, objTracking, item, itemAsObj, typeExpr, serializer, elementType); } Func <int, Expression, Expression> makeArrayLoop = (loopRank, innerExpr) => { var loopRankIndex = Expression.Parameter(typeof(int), "loopRankIndex" + loopRank); variables.Add(loopRankIndex); var loopExpressions = new List <Expression>(); if (rank == 1) { loopExpressions.Add(Expression.Assign(item, Expression.ArrayAccess(arr, loopRankIndex))); } else { loopExpressions.Add(Expression.Assign(Expression.ArrayAccess(indices, Expression.Constant(loopRank)), loopRankIndex)); loopExpressions.Add(Expression.Assign(item, Expression.Convert(Expression.Call(arr, ArrayMih.GetValueRank(), indices), elementType))); } loopExpressions.Add(innerExpr); loopExpressions.Add(Expression.Assign(loopRankIndex, Expression.Add(loopRankIndex, Expression.Constant(1)))); var cond = Expression.LessThan(loopRankIndex, Expression.ArrayIndex(lengths, Expression.Constant(loopRank))); var loopBody = Expression.Block(loopExpressions); var breakLabel = Expression.Label("breakLabel" + loopRank); var loop = Expression.Loop(Expression.IfThenElse(cond, loopBody, Expression.Break(breakLabel)), breakLabel); return(Expression.Block(Expression.Assign(loopRankIndex, Expression.Constant(0)), loop)); }; for (int r = rank - 1; r >= 0; r--) { innerExpression = makeArrayLoop(r, innerExpression); } expressions.Add(innerExpression); return(expressions); }