From e06157d1f82b863ad50a812a9651b8678457fa45 Mon Sep 17 00:00:00 2001 From: Suremaker Date: Sun, 6 Apr 2014 16:11:49 +0100 Subject: [PATCH 1/2] + changed BuildContext/TypeMembersSerializerBuilder/TypeSerializerBuilder to generate methods with proper type instead of object, removed casting + changed collections / arrays / classes serialization to use generic methods of TypeSerializerFactory --- Changelog.txt | 4 + ObjectSerialization/Builders/BuildContext.cs | 112 +++++----- .../Builders/TypeMembersSerializerBuilder.cs | 210 +++++++++--------- .../Builders/TypeSerializerBuilder.cs | 18 +- .../Builders/Types/ArrayTypeSerializer.cs | 30 +-- .../Builders/Types/BaseTypeSerializer.cs | 178 ++++++++------- .../Builders/Types/ClassTypeSerializer.cs | 4 +- .../Types/CollectionTypeSerializer.cs | 16 +- .../Builders/Types/ValueTypeSerializer.cs | 4 +- .../Factories/TypeSerializerFactory.cs | 15 +- .../Types/TypeInfoRepository.cs | 4 +- 11 files changed, 325 insertions(+), 270 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 687720e..7c3fd59 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,10 @@ ObjectSerialization =========================================== +Version 1.0.27 +------------------------------------------- ++ Optimized collections / arrays serialization by using generic methods of TypeSerializerFactory + Version 1.0.26 ------------------------------------------- + ensured proper and constant order of registered types with TypeInfoRepository.RegisterPredefinedUsingSerializableFrom diff --git a/ObjectSerialization/Builders/BuildContext.cs b/ObjectSerialization/Builders/BuildContext.cs index 7be7196..e559baa 100644 --- a/ObjectSerialization/Builders/BuildContext.cs +++ b/ObjectSerialization/Builders/BuildContext.cs @@ -8,76 +8,78 @@ namespace ObjectSerialization.Builders { - internal class BuildContext - { - public readonly LabelTarget ReadReturnLabel = Expression.Label(typeof(object), "ret"); - public readonly ParameterExpression ReaderObject = Expression.Parameter(typeof(BinaryReader), "r"); + internal class BuildContext + { + public readonly LabelTarget ReadReturnLabel = Expression.Label(typeof(T), "ret"); + public readonly ParameterExpression ReaderObject = Expression.Parameter(typeof(BinaryReader), "r"); - public readonly ParameterExpression WriteObject = Expression.Variable(typeof(T), "v"); - public readonly ParameterExpression WriterObject = Expression.Parameter(typeof(BinaryWriter), "w"); - private readonly List _readExpressions = new List(); - private readonly List _writeExpressions = new List(); - private readonly ParameterExpression _writeParameter = Expression.Parameter(typeof(object), "o"); - public ParameterExpression ReadResultObject { get; private set; } + public readonly ParameterExpression WriteObject = Expression.Parameter(typeof(T), "o"); + public readonly ParameterExpression WriterObject = Expression.Parameter(typeof(BinaryWriter), "w"); + private readonly List _readExpressions = new List(); + private readonly List _writeExpressions = new List(); + public ParameterExpression ReadResultObject { get; private set; } - public BuildContext() - { - _writeExpressions.Add(Expression.Assign(WriteObject, Expression.Convert(_writeParameter, typeof(T)))); - } + public BuildContext() + { + } - public BuildContext(ParameterExpression readResult) - : this() - { - ReadResultObject = readResult; - _readExpressions.Add(Expression.Assign(ReadResultObject, BaseTypeSerializer.InstantiateNew(typeof(T)))); - } + public BuildContext(ParameterExpression readResult) + : this() + { + ReadResultObject = readResult; + _readExpressions.Add(Expression.Assign(ReadResultObject, BaseTypeSerializer.InstantiateNew(typeof(T)))); + } - public void AddReadExpression(Expression expr) - { - _readExpressions.Add(expr); - } + public void AddReadExpression(Expression expr) + { + _readExpressions.Add(expr); + } - public void AddWriteExpression(Expression expr) - { - _writeExpressions.Add(expr); - } + public void AddWriteExpression(Expression expr) + { + _writeExpressions.Add(expr); + } - public Func GetDeserializeFn() - { - if (ReadResultObject != null) - _readExpressions.Add(ReturnValue(ReadResultObject)); + public Func GetDeserializeFn() + { + if (ReadResultObject != null) + _readExpressions.Add(ReturnValue(ReadResultObject)); - List expressions = _readExpressions.ToList(); + List expressions = _readExpressions.ToList(); - expressions.Add(Expression.Label(ReadReturnLabel, Expression.Convert(Expression.Default(typeof(T)), typeof(object)))); - Expression body = Expression.Block(ReadResultObject == null ? null : new[] { ReadResultObject }, expressions); - Expression> expression = Expression.Lambda>(body, ReaderObject); + expressions.Add(Expression.Label(ReadReturnLabel, Expression.Default(typeof(T)))); + Expression body = Expression.Block(ReadResultObject == null ? null : new[] { ReadResultObject }, expressions); + Expression> expression = Expression.Lambda>(body, ReaderObject); #if DEBUG DumpExpression("Deserialize", expression); #endif - return expression.Compile(); - } + return expression.Compile(); + } - public Action GetSerializeFn() - { - BlockExpression blockExpression = Expression.Block(new[] { WriteObject }, _writeExpressions); - Expression> expression = Expression.Lambda>(blockExpression, WriterObject, _writeParameter); + public Action GetSerializeFn() + { + Expression body = !_writeExpressions.Any() + ? Expression.Empty() + : (_writeExpressions.Count == 1) + ? _writeExpressions[0] + : Expression.Block(_writeExpressions); + Expression> expression = Expression.Lambda>(body, WriterObject, WriteObject); #if DEBUG DumpExpression("Serialize", expression); #endif - return expression.Compile(); - } + return expression.Compile(); + } - public Expression ReturnValue(Expression result) - { - return Expression.Return(ReadReturnLabel, Expression.Convert(result, typeof(object)), typeof(object)); - } + public Expression ReturnValue(Expression result) + { + return Expression.Return(ReadReturnLabel, result, typeof(T)); + } - private void DumpExpression(string operation, Expression expression) - { - object value = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) - .GetValue(expression, null); - Console.Write("{0} {1}: {2}\n", typeof(T).Name, operation, value); - } - } + private void DumpExpression(string operation, Expression expression) + { + object value = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) + .GetValue(expression, null); + Console.Write("{0} {1}: {2}\n", typeof(T).Name, operation, value); + } + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs b/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs index c281cb4..2ac2f19 100644 --- a/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs +++ b/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.Serialization; -using ObjectSerialization.Builders.Types; - -namespace ObjectSerialization.Builders -{ - internal class TypeMembersSerializerBuilder : SerializerBuilder - { - private static Func _deserializeFn; - private static Action _serializeFn; - - public static Func DeserializeFn - { - get - { - if (_deserializeFn == null) - Build(); - return _deserializeFn; - } - } - - public static Action SerializeFn - { - get - { - if (_serializeFn == null) - Build(); - return _serializeFn; - } - } - - public static IEnumerable GetFields(Type type) - { - if (type == null) - return Enumerable.Empty(); - - return type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) - .Concat(GetFields(type.BaseType)); - } - - private static void Build() - { - try - { - var ctx = new BuildContext(Expression.Variable(typeof(T), "o")); - - IOrderedEnumerable fields = GetFields(typeof(T)) - .Where(ShouldBePersisted) - .OrderBy(f => f.Name); - - foreach (FieldInfo field in fields) - BuildFieldSerializer(field, ctx); - - _serializeFn = ctx.GetSerializeFn(); - _deserializeFn = ctx.GetDeserializeFn(); - } - catch (Exception e) - { - throw new SerializationException(e.Message, e); - } - } - - private static void BuildFieldSerializer(FieldInfo field, BuildContext ctx) - { - if (field.IsInitOnly) - throw new InvalidOperationException(string.Format("Unable to serialize readonly field {0} in type {1}. Please mark it with NonSerialized attribute or remove readonly modifier.", field.Name, typeof(T).FullName)); - - ISerializer serializer = Serializers.First(s => s.IsSupported(field.FieldType)); - ctx.AddWriteExpression(serializer.Write(ctx.WriterObject, GetFieldValue(ctx.WriteObject, field), field.FieldType)); - ctx.AddReadExpression(SetFieldValue(ctx.ReadResultObject, field, serializer.Read(ctx.ReaderObject, field.FieldType))); - } - - private static Expression GetFieldValue(Expression instance, FieldInfo field) - { - return Expression.Field(instance, field); - } - - private static PropertyInfo GetPropertyForBackingField(FieldInfo field) - { - string propertyName = field.Name.Substring(1, field.Name.IndexOf('>') - 1); - PropertyInfo propertyForBackingField = field.DeclaringType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - return propertyForBackingField; - } - - private static Expression SetFieldValue(Expression instance, FieldInfo field, Expression valueExpression) - { - return Expression.Assign(Expression.Field(instance, field), valueExpression); - } - - private static bool ShouldBePersisted(FieldInfo field) - { - if (field.GetCustomAttributes(typeof(NonSerializedAttribute), true).Length > 0) - return false; - - if (field.Name.EndsWith("k__BackingField") && GetPropertyForBackingField(field).GetCustomAttributes(typeof(NonSerializedBackendAttribute), true).Length > 0) - return false; - - return true; - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.Serialization; +using ObjectSerialization.Builders.Types; + +namespace ObjectSerialization.Builders +{ + internal class TypeMembersSerializerBuilder : SerializerBuilder + { + private static Func _deserializeFn; + private static Action _serializeFn; + + public static Func DeserializeFn + { + get + { + if (_deserializeFn == null) + Build(); + return _deserializeFn; + } + } + + public static Action SerializeFn + { + get + { + if (_serializeFn == null) + Build(); + return _serializeFn; + } + } + + public static IEnumerable GetFields(Type type) + { + if (type == null) + return Enumerable.Empty(); + + return type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Concat(GetFields(type.BaseType)); + } + + private static void Build() + { + try + { + var ctx = new BuildContext(Expression.Variable(typeof(T), "o")); + + IOrderedEnumerable fields = GetFields(typeof(T)) + .Where(ShouldBePersisted) + .OrderBy(f => f.Name); + + foreach (FieldInfo field in fields) + BuildFieldSerializer(field, ctx); + + _serializeFn = ctx.GetSerializeFn(); + _deserializeFn = ctx.GetDeserializeFn(); + } + catch (Exception e) + { + throw new SerializationException(e.Message, e); + } + } + + private static void BuildFieldSerializer(FieldInfo field, BuildContext ctx) + { + if (field.IsInitOnly) + throw new InvalidOperationException(string.Format("Unable to serialize readonly field {0} in type {1}. Please mark it with NonSerialized attribute or remove readonly modifier.", field.Name, typeof(T).FullName)); + + ISerializer serializer = Serializers.First(s => s.IsSupported(field.FieldType)); + ctx.AddWriteExpression(serializer.Write(ctx.WriterObject, GetFieldValue(ctx.WriteObject, field), field.FieldType)); + ctx.AddReadExpression(SetFieldValue(ctx.ReadResultObject, field, serializer.Read(ctx.ReaderObject, field.FieldType))); + } + + private static Expression GetFieldValue(Expression instance, FieldInfo field) + { + return Expression.Field(instance, field); + } + + private static PropertyInfo GetPropertyForBackingField(FieldInfo field) + { + string propertyName = field.Name.Substring(1, field.Name.IndexOf('>') - 1); + PropertyInfo propertyForBackingField = field.DeclaringType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + return propertyForBackingField; + } + + private static Expression SetFieldValue(Expression instance, FieldInfo field, Expression valueExpression) + { + return Expression.Assign(Expression.Field(instance, field), valueExpression); + } + + private static bool ShouldBePersisted(FieldInfo field) + { + if (field.GetCustomAttributes(typeof(NonSerializedAttribute), true).Length > 0) + return false; + + if (field.Name.EndsWith("k__BackingField") && GetPropertyForBackingField(field).GetCustomAttributes(typeof(NonSerializedBackendAttribute), true).Length > 0) + return false; + + return true; + } + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/TypeSerializerBuilder.cs b/ObjectSerialization/Builders/TypeSerializerBuilder.cs index 346479b..3bb5403 100644 --- a/ObjectSerialization/Builders/TypeSerializerBuilder.cs +++ b/ObjectSerialization/Builders/TypeSerializerBuilder.cs @@ -7,10 +7,10 @@ namespace ObjectSerialization.Builders { internal class TypeSerializerBuilder : SerializerBuilder { - private static Func _deserializeFn; - private static Action _serializeFn; + private static Func _deserializeFn; + private static Action _serializeFn; - public static Func DeserializeFn + public static Func DeserializeFn { get { @@ -20,7 +20,7 @@ public static Func DeserializeFn } } - public static Action SerializeFn + public static Action SerializeFn { get { @@ -30,6 +30,16 @@ public static Action SerializeFn } } + public static void SerializeWithCast(BinaryWriter writer, object value) + { + SerializeFn(writer, (T)value); + } + + public static object DeserializeWithCast(BinaryReader reader) + { + return DeserializeFn(reader); + } + private static void Build() { var ctx = new BuildContext(); diff --git a/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs b/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs index e61d077..96979e4 100644 --- a/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs @@ -16,18 +16,18 @@ public bool IsSupported(Type type) public Expression Write(Expression writerObject, Expression value, Type valueType) { - /*BinaryWriter w; + /*BinaryWriter w; T[] v; if (v != null) { - w.Write(v.Length); - int c = v.Length; - int s = TypeSerializerFactory.GetSerializer(typeof(T)); - for (var i = 0; i < c; ++i) - s.Invoke(w, v[i]); + w.Write(v.Length); + int c = v.Length; + int s = TypeSerializerFactory.GetSerializer(); + for (var i = 0; i < c; ++i) + s.Invoke(w, v[i]); } else - w.Write(-1);*/ + w.Write(-1);*/ Expression checkNotNull = CheckNotNull(value, valueType); @@ -45,7 +45,7 @@ public Expression Read(Expression readerObject, Type expectedValueType) return null; T[]v=new T[c]; - int s = TypeSerializerFactory.GetDeserializer(typeof (T)); + int s = TypeSerializerFactory.GetDeserializer(); for(var i=0 ; i < c; ++i) v[i] = s.Invoke(r); return v; @@ -69,19 +69,19 @@ private static BlockExpression CreateWriteLoop(Expression writerObject, Expressi { ParameterExpression index = Expression.Parameter(typeof(int), "i"); ParameterExpression count = Expression.Parameter(typeof(int), "c"); - ParameterExpression serializer = Expression.Parameter(typeof(Action), "s"); + ParameterExpression serializer = Expression.Parameter(GetWriteSerializerDelegateType(valueType.GetElementType()), "s"); LabelTarget loopEndLabel = Expression.Label(); return Expression.Block( new[] { index, count, serializer }, Expression.Assign(index, Expression.Constant(0, typeof(int))), Expression.Assign(count, Expression.Property(value, "Length")), - Expression.Assign(serializer, GetSerializer(Expression.Constant(valueType.GetElementType()))), + Expression.Assign(serializer, GetSerializer(valueType.GetElementType())), Expression.Loop( Expression.IfThenElse( Expression.LessThan(index, count), Expression.Block( - CallSerializeWithConvert(serializer, Expression.ArrayAccess(value, index), writerObject), + CallSerialize(serializer, Expression.ArrayAccess(value, index), writerObject), Expression.PreIncrementAssign(index)), Expression.Break(loopEndLabel)), loopEndLabel)); @@ -90,7 +90,7 @@ private static BlockExpression CreateWriteLoop(Expression writerObject, Expressi private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, ParameterExpression count) { ParameterExpression index = Expression.Parameter(typeof(int), "i"); - ParameterExpression deserializer = Expression.Parameter(typeof(Func), "s"); + ParameterExpression deserializer = Expression.Parameter(GetReadSerializerDelegateType(expectedValueType.GetElementType()), "s"); ParameterExpression result = Expression.Parameter(expectedValueType, "r"); LabelTarget loopEndLabel = Expression.Label(expectedValueType); @@ -98,17 +98,19 @@ private Expression CreateReadLoop(Expression readerObject, Type expectedValueTyp new[] { index, result, deserializer }, Expression.Assign(result, Expression.NewArrayBounds(expectedValueType.GetElementType(), count)), Expression.Assign(index, Expression.Constant(0, typeof(int))), - Expression.Assign(deserializer, GetDeserializer(Expression.Constant(expectedValueType.GetElementType()))), + Expression.Assign(deserializer, GetDeserializer(expectedValueType.GetElementType())), Expression.Loop( Expression.IfThenElse( Expression.LessThan(index, count), Expression.Block( - Expression.Assign(Expression.ArrayAccess(result, index), CallDeserialize(deserializer, expectedValueType.GetElementType(), readerObject)), + Expression.Assign(Expression.ArrayAccess(result, index), CallDeserialize(deserializer, readerObject)), Expression.PreIncrementAssign(index)), Expression.Break(loopEndLabel, result)), loopEndLabel)); return forLoop; } + + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs b/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs index c5d84c9..f7da06a 100644 --- a/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs @@ -1,83 +1,109 @@ using System; +using System.IO; using System.Linq.Expressions; using System.Runtime.Serialization; namespace ObjectSerialization.Builders.Types { - internal class BaseTypeSerializer - { - public static Expression InstantiateNew(Type type) - { - if (type.IsClass && type.GetConstructor(new Type[0]) == null) - return Expression.TypeAs(Expression.Call(typeof(FormatterServices), "GetUninitializedObject", null, Expression.Constant(type)), type); - return Expression.New(type); - } - - protected static Expression CallDeserialize(Expression deserializer, Type propertyType, Expression readerObject) - { - return Expression.Convert(Expression.Call(deserializer, "Invoke", null, readerObject), propertyType); - } - - protected static Expression CallSerialize(Expression serializer, Expression value, Expression writerObject) - { - return Expression.Call(serializer, "Invoke", null, writerObject, value); - } - - protected static Expression CallSerializeWithConvert(Expression serializer, Expression value, Expression writerObject) - { - return Expression.Call(serializer, "Invoke", null, writerObject, Expression.Convert(value, typeof(object))); - } - - protected static Expression CheckNotNull(Expression value, Type valueType) - { - return Expression.ReferenceNotEqual(value, Expression.Constant(null, valueType)); - } - - protected static Expression GetActualValueType(Expression value) - { - return Expression.Call(Expression.TypeAs(value, typeof(object)), "GetType", null); - } - - protected static Expression GetDeserializer(Expression type) - { - return Expression.Call(typeof(TSerializerFactory), "GetDeserializer", null, type); - } - - protected static Expression GetReadExpression(string method, Expression reader) - { - return Expression.Call(reader, method, new Type[0]); - } - - protected static Expression GetSerializer(Expression type) - { - return Expression.Call(typeof(TSerializerFactory), "GetSerializer", null, type); - } - - protected static Expression GetWriteExpression(Expression valueExpression, Expression writer) - { - return Expression.Call(writer, "Write", null, valueExpression); - } - - protected static Expression ReloadType(Expression readerObject) - { - return GetReadExpression("ReadString", readerObject); - } - - protected static Expression WriteObjectType(Expression value, Expression objectWriter) - { - Expression valueType = GetActualValueType(value); - MemberExpression typeFullName = Expression.Property(valueType, "FullName"); - return GetWriteExpression(typeFullName, objectWriter); - } - - protected Expression GetDirectDeserializer(Type builderType, Type valueType) - { - return Expression.Property(null, builderType.MakeGenericType(valueType), "DeserializeFn"); - } - - protected Expression GetDirectSerializer(Type builderType, Type valueType) - { - return Expression.Property(null, builderType.MakeGenericType(valueType), "SerializeFn"); - } - } + internal class BaseTypeSerializer + { + public static Expression InstantiateNew(Type type) + { + if (type.IsClass && type.GetConstructor(new Type[0]) == null) + return Expression.TypeAs(Expression.Call(typeof(FormatterServices), "GetUninitializedObject", null, Expression.Constant(type)), type); + return Expression.New(type); + } + + protected static Expression CallDeserialize(Expression deserializer, Expression readerObject) + { + return Expression.Call(deserializer, "Invoke", null, readerObject); + } + + protected static Expression CallDeserializeWithConvert(Expression deserializer, Type propertyType, Expression readerObject) + { + return Expression.Convert(Expression.Call(deserializer, "Invoke", null, readerObject), propertyType); + } + + protected static Expression CallSerialize(Expression serializer, Expression value, Expression writerObject) + { + return Expression.Call(serializer, "Invoke", null, writerObject, value); + } + + protected static Expression CallSerializeWithConvert(Expression serializer, Expression value, Type valueType, Expression writerObject) + { + return Expression.Call(serializer, "Invoke", null, writerObject, Expression.Convert(value, valueType)); + } + + protected static Expression CheckNotNull(Expression value, Type valueType) + { + return Expression.ReferenceNotEqual(value, Expression.Constant(null, valueType)); + } + + protected static Expression GetActualValueType(Expression value) + { + return Expression.Call(Expression.TypeAs(value, typeof(object)), "GetType", null); + } + + protected static Expression GetDeserializer(Expression type) + { + return Expression.Call(typeof(TSerializerFactory), "GetDeserializer", null, type); + } + + protected static Expression GetDeserializer(Type type) + { + return Expression.Call(typeof(TSerializerFactory), "GetDeserializer", new[] { type }); + } + + protected static Expression GetReadExpression(string method, Expression reader) + { + return Expression.Call(reader, method, new Type[0]); + } + + protected static Expression GetSerializer(Expression type) + { + return Expression.Call(typeof(TSerializerFactory), "GetSerializer", null, type); + } + + protected static Expression GetSerializer(Type type) + { + return Expression.Call(typeof(TSerializerFactory), "GetSerializer", new[] { type }); + } + + protected static Expression GetWriteExpression(Expression valueExpression, Expression writer) + { + return Expression.Call(writer, "Write", null, valueExpression); + } + + protected static Expression ReloadType(Expression readerObject) + { + return GetReadExpression("ReadString", readerObject); + } + + protected static Expression WriteObjectType(Expression value, Expression objectWriter) + { + Expression valueType = GetActualValueType(value); + MemberExpression typeFullName = Expression.Property(valueType, "FullName"); + return GetWriteExpression(typeFullName, objectWriter); + } + + protected Expression GetDirectDeserializer(Type builderType, Type valueType) + { + return Expression.Property(null, builderType.MakeGenericType(valueType), "DeserializeFn"); + } + + protected Expression GetDirectSerializer(Type builderType, Type valueType) + { + return Expression.Property(null, builderType.MakeGenericType(valueType), "SerializeFn"); + } + + protected static Type GetWriteSerializerDelegateType(Type type) + { + return typeof(Action<,>).MakeGenericType(typeof(BinaryWriter), type); + } + + protected static Type GetReadSerializerDelegateType(Type type) + { + return typeof(Func<,>).MakeGenericType(typeof(BinaryReader), type); + } + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs b/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs index a04a4ef..b15b470 100644 --- a/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs @@ -63,8 +63,8 @@ public Expression Read(Expression readerObject, Type expectedValueType) ParameterExpression flag = Expression.Variable(typeof(byte), "b"); BinaryExpression readFlag = Expression.Assign(flag, GetReadExpression("ReadByte", readerObject)); - Expression deserializeClass = CallDeserialize(GetDirectDeserializer(typeof(TypeMembersSerializerBuilder<>), expectedValueType), expectedValueType, readerObject); - Expression deserializePolymorphic = CallDeserialize(GetDeserializerField(ReadTypeInfo(readerObject)), expectedValueType, readerObject); + Expression deserializeClass = CallDeserialize(GetDirectDeserializer(typeof(TypeMembersSerializerBuilder<>), expectedValueType), readerObject); + Expression deserializePolymorphic = CallDeserializeWithConvert(GetDeserializerField(ReadTypeInfo(readerObject)), expectedValueType, readerObject); ConditionalExpression deserialization = Expression.Condition( Expression.Equal(flag, Expression.Constant((byte)0)), diff --git a/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs b/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs index 3939b64..05aed91 100644 --- a/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs @@ -24,7 +24,7 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp if (v!= null) { w.Write(v.Count); - int s = TypeSerializerFactory.GetSerializer(typeof(T)); + int s = TypeSerializerFactory.GetSerializer(); IEnumerator e = v.GetEnumerator(); try @@ -59,7 +59,7 @@ public Expression Read(Expression readerObject, Type expectedValueType) return null; TCollection v=new TCollection(); - int s = TypeSerializerFactory.GetDeserializer(typeof(T)); + int s = TypeSerializerFactory.GetDeserializer(); for(var i=0 ; i < c; ++i) v.Add(s.Invoke(r)); return v;*/ @@ -92,7 +92,7 @@ private static Type GetCollectionType(Type type) private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, ParameterExpression count) { ParameterExpression index = Expression.Parameter(typeof(int), "i"); - ParameterExpression deserializer = Expression.Parameter(typeof(Func), "s"); + ParameterExpression deserializer = Expression.Parameter(GetReadSerializerDelegateType(GetCollectionItemType(expectedValueType)), "s"); ParameterExpression result = Expression.Parameter(expectedValueType, "v"); LabelTarget loopEndLabel = Expression.Label(expectedValueType); @@ -100,12 +100,12 @@ private Expression CreateReadLoop(Expression readerObject, Type expectedValueTyp new[] { index, result, deserializer }, Expression.Assign(result, InstantiateNew(expectedValueType)), Expression.Assign(index, Expression.Constant(0, typeof(int))), - Expression.Assign(deserializer, GetDeserializer(Expression.Constant(GetCollectionItemType(expectedValueType)))), + Expression.Assign(deserializer, GetDeserializer(GetCollectionItemType(expectedValueType))), Expression.Loop( Expression.IfThenElse( Expression.LessThan(index, count), Expression.Block( - Expression.Call(Expression.TypeAs(result, GetCollectionType(expectedValueType)), "Add", null, CallDeserialize(deserializer, GetCollectionItemType(expectedValueType), readerObject)), + Expression.Call(Expression.TypeAs(result, GetCollectionType(expectedValueType)), "Add", null, CallDeserialize(deserializer, readerObject)), Expression.PreIncrementAssign(index)), Expression.Break(loopEndLabel, result)), loopEndLabel)); @@ -117,18 +117,18 @@ private Expression CreateWriteLoop(Expression writerObject, Expression value, Ty { Type enumeratorType = GetEnumeratorType(valueType); ParameterExpression enumerator = Expression.Parameter(enumeratorType, "e"); - ParameterExpression serializer = Expression.Parameter(typeof(Action), "s"); + ParameterExpression serializer = Expression.Parameter(GetWriteSerializerDelegateType(GetCollectionItemType(valueType)), "s"); LabelTarget loopEndLabel = Expression.Label(); return Expression.Block( new[] { enumerator, serializer }, - Expression.Assign(serializer, GetSerializer(Expression.Constant(GetCollectionItemType(valueType)))), + Expression.Assign(serializer, GetSerializer(GetCollectionItemType(valueType))), Expression.Assign(enumerator, Expression.Convert(Expression.Call(value, "GetEnumerator", null), enumeratorType)), Expression.TryFinally( Expression.Loop( Expression.IfThenElse( Expression.Call(Expression.TypeAs(enumerator, typeof(IEnumerator)), "MoveNext", null), - CallSerializeWithConvert(serializer, Expression.Property(enumerator, "Current"), writerObject), + CallSerialize(serializer, Expression.Property(enumerator, "Current"), writerObject), Expression.Break(loopEndLabel)), loopEndLabel), Expression.Call(Expression.TypeAs(enumerator, typeof(IDisposable)), "Dispose", null))); diff --git a/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs b/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs index 93d49ea..912b18e 100644 --- a/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs @@ -19,7 +19,7 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp TypeMembersSerializerBuilder.SerializeFn.Invoke(w, v); */ - return CallSerializeWithConvert(GetDirectSerializer(typeof(TypeMembersSerializerBuilder<>),valueType), value, writerObject); + return CallSerialize(GetDirectSerializer(typeof(TypeMembersSerializerBuilder<>),valueType), value, writerObject); } public Expression Read(Expression readerObject, Type expectedValueType) @@ -27,7 +27,7 @@ public Expression Read(Expression readerObject, Type expectedValueType) /*BinaryReader r; return TypeMembersSerializerBuilder.DeserializeFn.Invoke(r) */ - return CallDeserialize(GetDirectDeserializer(typeof(TypeMembersSerializerBuilder<>), expectedValueType), expectedValueType, readerObject); + return CallDeserialize(GetDirectDeserializer(typeof(TypeMembersSerializerBuilder<>), expectedValueType), readerObject); } #endregion diff --git a/ObjectSerialization/Factories/TypeSerializerFactory.cs b/ObjectSerialization/Factories/TypeSerializerFactory.cs index 079dce3..598ec8c 100644 --- a/ObjectSerialization/Factories/TypeSerializerFactory.cs +++ b/ObjectSerialization/Factories/TypeSerializerFactory.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using ObjectSerialization.Builders; using ObjectSerialization.Types; namespace ObjectSerialization.Factories @@ -8,12 +9,17 @@ internal class TypeSerializerFactory { public static Func GetDeserializer(string typeFullName) { - return TypeInfoRepository.GetTypeInfo(typeFullName).Deserializer; + return TypeInfoRepository.GetTypeInfo(typeFullName).Deserializer; } public static Func GetDeserializer(Type type) { - return TypeInfoRepository.GetTypeInfo(type).Deserializer; + return TypeInfoRepository.GetTypeInfo(type).Deserializer; + } + + public static Func GetDeserializer() + { + return TypeSerializerBuilder.DeserializeFn; } public static Action GetSerializer(string typeFullName) @@ -25,5 +31,10 @@ public static Action GetSerializer(Type type) { return TypeInfoRepository.GetTypeInfo(type).Serializer; } + + public static Action GetSerializer() + { + return TypeSerializerBuilder.SerializeFn; + } } } \ No newline at end of file diff --git a/ObjectSerialization/Types/TypeInfoRepository.cs b/ObjectSerialization/Types/TypeInfoRepository.cs index 1605f4b..97829ce 100644 --- a/ObjectSerialization/Types/TypeInfoRepository.cs +++ b/ObjectSerialization/Types/TypeInfoRepository.cs @@ -115,8 +115,8 @@ private static TypeInfo LoadTypeInfo(Type type) Type = type, LongTypeId = type.FullName, ShortTypeId = null, - Serializer = (Action)builderType.GetProperty("SerializeFn", BindingFlags.Static | BindingFlags.Public).GetValue(null, null), - Deserializer = (Func)builderType.GetProperty("DeserializeFn", BindingFlags.Static | BindingFlags.Public).GetValue(null, null) + Serializer = (Action)Delegate.CreateDelegate(typeof(Action), builderType.GetMethod("SerializeWithCast", BindingFlags.Static | BindingFlags.Public)), + Deserializer = (Func)Delegate.CreateDelegate(typeof(Func), builderType.GetMethod("DeserializeWithCast", BindingFlags.Static | BindingFlags.Public)) }; } } From df3d1f97145801b55b933ca62d80c2a38ac1f223 Mon Sep 17 00:00:00 2001 From: Suremaker Date: Mon, 19 May 2014 21:34:22 +0100 Subject: [PATCH 2/2] replaced lambda expressions with code builder --- ObjectSerialization.Performance/Program.cs | 4 +- .../TestCases/TestCase.cs | 2 +- ObjectSerialization.sln | 28 ++- ObjectSerialization/Builders/BuildContext.cs | 127 ++++++----- .../Builders/TypeMembersSerializerBuilder.cs | 11 +- .../Builders/TypeSerializerBuilder.cs | 2 +- .../Builders/Types/ArrayTypeSerializer.cs | 98 ++++----- .../Builders/Types/BaseTypeSerializer.cs | 207 +++++++++--------- .../Builders/Types/ClassTypeSerializer.cs | 49 +++-- .../Types/CollectionTypeSerializer.cs | 91 ++++---- .../Builders/Types/ISerializer.cs | 2 +- .../Types/PredefinedTypeSerializer.cs | 2 +- .../Builders/Types/StringTypeSerializer.cs | 11 +- .../Builders/Types/ValueTypeSerializer.cs | 2 +- .../ObjectSerialization.csproj | 6 + 15 files changed, 334 insertions(+), 308 deletions(-) diff --git a/ObjectSerialization.Performance/Program.cs b/ObjectSerialization.Performance/Program.cs index b2e3686..8950cae 100644 --- a/ObjectSerialization.Performance/Program.cs +++ b/ObjectSerialization.Performance/Program.cs @@ -15,11 +15,11 @@ class Program static void Main() { var monitor = new PerformanceMonitor( - new ObjectSerializerAdapter(), + new ObjectSerializerAdapter()/*, new BinaryFormatterAdapter(), new ProtoBufAdapter(), new NewtonBsonAdapter(), - new DataContractSerializerAdapter()); + new DataContractSerializerAdapter()*/); Console.WriteLine("Press enter to start"); Console.ReadLine(); diff --git a/ObjectSerialization.Performance/TestCases/TestCase.cs b/ObjectSerialization.Performance/TestCases/TestCase.cs index 7094d3e..4e12fc3 100644 --- a/ObjectSerialization.Performance/TestCases/TestCase.cs +++ b/ObjectSerialization.Performance/TestCases/TestCase.cs @@ -8,7 +8,7 @@ namespace ObjectSerialization.Performance.TestCases { abstract class TestCase { - private const int _measurementCount = 250000; + private const int _measurementCount = 200000; public abstract string Name { get; } public PerformanceResult Measure(ISerializerAdapter serializer) { diff --git a/ObjectSerialization.sln b/ObjectSerialization.sln index a52259e..0e59410 100644 --- a/ObjectSerialization.sln +++ b/ObjectSerialization.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectSerialization", "ObjectSerialization\ObjectSerialization.csproj", "{32D2BED8-AE96-4E80-A981-5188FEB260D4}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectSerialization.UT", "ObjectSerialization.UT\ObjectSerialization.UT.csproj", "{25015080-9E1B-49F2-9F1F-D22C1418B25F}" @@ -13,6 +13,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectSerialization.Performance", "ObjectSerialization.Performance\ObjectSerialization.Performance.csproj", "{724404A9-0638-4378-A0BC-D76B62FB0E3A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeBuilder", "..\CodeBuilder\CodeBuilder\CodeBuilder.csproj", "{22256B91-E772-40A0-BED3-AA6E10EEF1E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeBuilder.UT", "..\CodeBuilder\CodeBuilder.UT\CodeBuilder.UT.csproj", "{900FC247-1330-4CBA-A1C7-A450993065C5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,6 +57,26 @@ Global {724404A9-0638-4378-A0BC-D76B62FB0E3A}.Release|Mixed Platforms.Build.0 = Release|x86 {724404A9-0638-4378-A0BC-D76B62FB0E3A}.Release|x86.ActiveCfg = Release|x86 {724404A9-0638-4378-A0BC-D76B62FB0E3A}.Release|x86.Build.0 = Release|x86 + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Release|Any CPU.Build.0 = Release|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {22256B91-E772-40A0-BED3-AA6E10EEF1E5}.Release|x86.ActiveCfg = Release|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Debug|x86.ActiveCfg = Debug|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Release|Any CPU.Build.0 = Release|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {900FC247-1330-4CBA-A1C7-A450993065C5}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ObjectSerialization/Builders/BuildContext.cs b/ObjectSerialization/Builders/BuildContext.cs index e559baa..36ea5fd 100644 --- a/ObjectSerialization/Builders/BuildContext.cs +++ b/ObjectSerialization/Builders/BuildContext.cs @@ -1,85 +1,82 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; +using System.Reflection.Emit; +using CodeBuilder; +using CodeBuilder.Expressions; using ObjectSerialization.Builders.Types; namespace ObjectSerialization.Builders { - internal class BuildContext - { - public readonly LabelTarget ReadReturnLabel = Expression.Label(typeof(T), "ret"); - public readonly ParameterExpression ReaderObject = Expression.Parameter(typeof(BinaryReader), "r"); + internal class BuildContext + { + private readonly string _suffix; + public readonly Expression ReaderObject = Expr.Parameter(0, typeof(BinaryReader)); - public readonly ParameterExpression WriteObject = Expression.Parameter(typeof(T), "o"); - public readonly ParameterExpression WriterObject = Expression.Parameter(typeof(BinaryWriter), "w"); - private readonly List _readExpressions = new List(); - private readonly List _writeExpressions = new List(); - public ParameterExpression ReadResultObject { get; private set; } + public readonly Expression WriteObject = Expr.Parameter(1, typeof(T)); + public readonly Expression WriterObject = Expr.Parameter(0, typeof(BinaryWriter)); + private readonly List _readExpressions = new List(); + private readonly List _writeExpressions = new List(); + public LocalVariable ReadResultObject { get; private set; } - public BuildContext() - { - } + public BuildContext(string suffix) + { + _suffix = suffix; + } - public BuildContext(ParameterExpression readResult) - : this() - { - ReadResultObject = readResult; - _readExpressions.Add(Expression.Assign(ReadResultObject, BaseTypeSerializer.InstantiateNew(typeof(T)))); - } + public BuildContext(LocalVariable readResult, string suffix) + : this(suffix) + { + ReadResultObject = readResult; + _readExpressions.Add(Expr.DeclareLocal(ReadResultObject, BaseTypeSerializer.InstantiateNew(typeof(T)))); + } - public void AddReadExpression(Expression expr) - { - _readExpressions.Add(expr); - } + public void AddReadExpression(Expression expr) + { + _readExpressions.Add(expr); + } - public void AddWriteExpression(Expression expr) - { - _writeExpressions.Add(expr); - } + public void AddWriteExpression(Expression expr) + { + _writeExpressions.Add(expr); + } - public Func GetDeserializeFn() - { - if (ReadResultObject != null) - _readExpressions.Add(ReturnValue(ReadResultObject)); + public Func GetDeserializeFn() + { + if (ReadResultObject != null) + _readExpressions.Add(Expr.Return(Expr.ReadLocal(ReadResultObject))); - List expressions = _readExpressions.ToList(); + return DefineMethod>("Deserialize", typeof(T), new[] { typeof(BinaryReader) }, _readExpressions.ToArray()); - expressions.Add(Expression.Label(ReadReturnLabel, Expression.Default(typeof(T)))); - Expression body = Expression.Block(ReadResultObject == null ? null : new[] { ReadResultObject }, expressions); - Expression> expression = Expression.Lambda>(body, ReaderObject); -#if DEBUG - DumpExpression("Deserialize", expression); -#endif - return expression.Compile(); - } + } + + public Action GetSerializeFn() + { + return DefineMethod>("Serialize", typeof(void), new[] { typeof(BinaryWriter), typeof(T) }, _writeExpressions.ToArray()); + } + + public Expression ReturnValue(Expression result) + { + return Expr.Return(result); + } - public Action GetSerializeFn() - { - Expression body = !_writeExpressions.Any() - ? Expression.Empty() - : (_writeExpressions.Count == 1) - ? _writeExpressions[0] - : Expression.Block(_writeExpressions); - Expression> expression = Expression.Lambda>(body, WriterObject, WriteObject); + private void DumpExpression(DynamicMethod method, MethodBodyBuilder builder) + { + Console.Write("{0} {1}:\n{2}\n\n", typeof(T).Name, method.Name, builder); + } + + private T DefineMethod(string name, Type returnType, Type[] parameters, params Expression[] body) + { + var method = new DynamicMethod(name + _suffix, returnType, parameters, true); + + var bodyBuilder = new MethodBodyBuilder(method, parameters); + bodyBuilder.AddStatements(body); #if DEBUG - DumpExpression("Serialize", expression); + DumpExpression(method, bodyBuilder); #endif - return expression.Compile(); - } - - public Expression ReturnValue(Expression result) - { - return Expression.Return(ReadReturnLabel, result, typeof(T)); - } + bodyBuilder.Compile(); - private void DumpExpression(string operation, Expression expression) - { - object value = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) - .GetValue(expression, null); - Console.Write("{0} {1}: {2}\n", typeof(T).Name, operation, value); - } - } + return (T)(object)method.CreateDelegate(typeof(T)); + } + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs b/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs index 2ac2f19..21b7b5c 100644 --- a/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs +++ b/ObjectSerialization/Builders/TypeMembersSerializerBuilder.cs @@ -2,9 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Reflection; using System.Runtime.Serialization; +using CodeBuilder; +using CodeBuilder.Expressions; using ObjectSerialization.Builders.Types; namespace ObjectSerialization.Builders @@ -47,7 +48,7 @@ private static void Build() { try { - var ctx = new BuildContext(Expression.Variable(typeof(T), "o")); + var ctx = new BuildContext(Expr.LocalVariable(typeof(T), "o"), "Members"); IOrderedEnumerable fields = GetFields(typeof(T)) .Where(ShouldBePersisted) @@ -72,12 +73,12 @@ private static void BuildFieldSerializer(FieldInfo field, BuildContext ctx) ISerializer serializer = Serializers.First(s => s.IsSupported(field.FieldType)); ctx.AddWriteExpression(serializer.Write(ctx.WriterObject, GetFieldValue(ctx.WriteObject, field), field.FieldType)); - ctx.AddReadExpression(SetFieldValue(ctx.ReadResultObject, field, serializer.Read(ctx.ReaderObject, field.FieldType))); + ctx.AddReadExpression(SetFieldValue(Expr.ReadLocal(ctx.ReadResultObject), field, serializer.Read(ctx.ReaderObject, field.FieldType))); } private static Expression GetFieldValue(Expression instance, FieldInfo field) { - return Expression.Field(instance, field); + return Expr.ReadField(instance, field); } private static PropertyInfo GetPropertyForBackingField(FieldInfo field) @@ -89,7 +90,7 @@ private static PropertyInfo GetPropertyForBackingField(FieldInfo field) private static Expression SetFieldValue(Expression instance, FieldInfo field, Expression valueExpression) { - return Expression.Assign(Expression.Field(instance, field), valueExpression); + return Expr.WriteField(instance, field, valueExpression); } private static bool ShouldBePersisted(FieldInfo field) diff --git a/ObjectSerialization/Builders/TypeSerializerBuilder.cs b/ObjectSerialization/Builders/TypeSerializerBuilder.cs index 3bb5403..ddc73f7 100644 --- a/ObjectSerialization/Builders/TypeSerializerBuilder.cs +++ b/ObjectSerialization/Builders/TypeSerializerBuilder.cs @@ -42,7 +42,7 @@ public static object DeserializeWithCast(BinaryReader reader) private static void Build() { - var ctx = new BuildContext(); + var ctx = new BuildContext(""); BuildTypeSerializer(typeof(T), ctx); _serializeFn = ctx.GetSerializeFn(); _deserializeFn = ctx.GetDeserializeFn(); diff --git a/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs b/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs index 96979e4..f62a9b9 100644 --- a/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ArrayTypeSerializer.cs @@ -1,6 +1,6 @@ using System; -using System.IO; -using System.Linq.Expressions; +using CodeBuilder; +using CodeBuilder.Expressions; using ObjectSerialization.Factories; namespace ObjectSerialization.Builders.Types @@ -29,12 +29,12 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp else w.Write(-1);*/ - Expression checkNotNull = CheckNotNull(value, valueType); + var checkNotNull = CheckNotNull(value, valueType); - BlockExpression forLoop = CreateWriteLoop(writerObject, value, valueType); - BlockExpression arrayWrite = Expression.Block(GetWriteExpression(Expression.Property(value, "Length"), writerObject), forLoop); + var forLoop = CreateWriteLoop(writerObject, value, valueType); + var arrayWrite = Expr.Block(GetWriteExpression(Expr.ArrayLength(value), writerObject), forLoop); - return Expression.IfThenElse(checkNotNull, arrayWrite, GetWriteExpression(Expression.Constant(-1), writerObject)); + return Expr.IfThenElse(checkNotNull, arrayWrite, GetWriteExpression(Expr.Constant(-1), writerObject)); } public Expression Read(Expression readerObject, Type expectedValueType) @@ -51,66 +51,62 @@ public Expression Read(Expression readerObject, Type expectedValueType) return v; */ - ParameterExpression count = Expression.Variable(typeof(int), "c"); - BinaryExpression countRead = Expression.Assign(count, GetReadExpression("ReadInt32", readerObject)); + var count = Expr.LocalVariable(typeof(int), "c"); + var countRead = Expr.DeclareLocal(count, GetReadExpression("ReadInt32", readerObject)); - BlockExpression expression = Expression.Block(new[] { count }, + var expression = Expr.ValueBlock( + expectedValueType, countRead, - Expression.Condition( - Expression.Equal(count, Expression.Constant(-1)), - Expression.Constant(null, expectedValueType), + Expr.IfThenElse( + Expr.Equal(Expr.ReadLocal(count), Expr.Constant(-1)), + Expr.Null(expectedValueType), CreateReadLoop(readerObject, expectedValueType, count))); return expression; } #endregion - private static BlockExpression CreateWriteLoop(Expression writerObject, Expression value, Type valueType) + private static Expression CreateWriteLoop(Expression writerObject, Expression value, Type valueType) { - ParameterExpression index = Expression.Parameter(typeof(int), "i"); - ParameterExpression count = Expression.Parameter(typeof(int), "c"); - ParameterExpression serializer = Expression.Parameter(GetWriteSerializerDelegateType(valueType.GetElementType()), "s"); - LabelTarget loopEndLabel = Expression.Label(); - - return Expression.Block( - new[] { index, count, serializer }, - Expression.Assign(index, Expression.Constant(0, typeof(int))), - Expression.Assign(count, Expression.Property(value, "Length")), - Expression.Assign(serializer, GetSerializer(valueType.GetElementType())), - Expression.Loop( - Expression.IfThenElse( - Expression.LessThan(index, count), - Expression.Block( - CallSerialize(serializer, Expression.ArrayAccess(value, index), writerObject), - Expression.PreIncrementAssign(index)), - Expression.Break(loopEndLabel)), - loopEndLabel)); + var index = Expr.LocalVariable(typeof(int), "i"); + var count = Expr.LocalVariable(typeof(int), "c"); + var serializer = Expr.LocalVariable(GetWriteSerializerDelegateType(valueType.GetElementType()), "s"); + + return Expr.Block( + Expr.DeclareLocal(index, Expr.Constant(0)), + Expr.DeclareLocal(count, Expr.ArrayLength(value)), + Expr.DeclareLocal(serializer, GetSerializer(valueType.GetElementType())), + Expr.Loop( + Expr.IfThenElse( + Expr.Less(Expr.ReadLocal(index), Expr.ReadLocal(count)), + Expr.Block( + CallSerialize(Expr.ReadLocal(serializer), Expr.ReadArray(value, Expr.ReadLocal(index)), writerObject), + Expr.WriteLocal(index, Expr.Add(Expr.ReadLocal(index), Expr.Constant(1)))), + Expr.LoopBreak()))); } - private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, ParameterExpression count) + private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, LocalVariable count) { - ParameterExpression index = Expression.Parameter(typeof(int), "i"); - ParameterExpression deserializer = Expression.Parameter(GetReadSerializerDelegateType(expectedValueType.GetElementType()), "s"); - ParameterExpression result = Expression.Parameter(expectedValueType, "r"); - LabelTarget loopEndLabel = Expression.Label(expectedValueType); - - BlockExpression forLoop = Expression.Block( - new[] { index, result, deserializer }, - Expression.Assign(result, Expression.NewArrayBounds(expectedValueType.GetElementType(), count)), - Expression.Assign(index, Expression.Constant(0, typeof(int))), - Expression.Assign(deserializer, GetDeserializer(expectedValueType.GetElementType())), - Expression.Loop( - Expression.IfThenElse( - Expression.LessThan(index, count), - Expression.Block( - Expression.Assign(Expression.ArrayAccess(result, index), CallDeserialize(deserializer, readerObject)), - Expression.PreIncrementAssign(index)), - Expression.Break(loopEndLabel, result)), - loopEndLabel)); + var index = Expr.LocalVariable(typeof(int), "i"); + var deserializer = Expr.LocalVariable(GetReadSerializerDelegateType(expectedValueType.GetElementType()), "s"); + var result = Expr.LocalVariable(expectedValueType, "r"); + + var forLoop = Expr.ValueBlock( + expectedValueType, + Expr.DeclareLocal(result, Expr.NewArray(expectedValueType.GetElementType(), Expr.ReadLocal(count))), + Expr.DeclareLocal(index, Expr.Constant(0)), + Expr.DeclareLocal(deserializer, GetDeserializer(expectedValueType.GetElementType())), + Expr.Loop( + Expr.IfThenElse( + Expr.Less(Expr.ReadLocal(index), Expr.ReadLocal(count)), + Expr.Block( + Expr.WriteArray(Expr.ReadLocal(result), Expr.ReadLocal(index), CallDeserialize(Expr.ReadLocal(deserializer), readerObject)), + Expr.WriteLocal(index, Expr.Add(Expr.ReadLocal(index), Expr.Constant(1)))), + Expr.LoopBreak())), + Expr.ReadLocal(result)); return forLoop; } - } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs b/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs index f7da06a..d083cd2 100644 --- a/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/BaseTypeSerializer.cs @@ -1,109 +1,112 @@ using System; using System.IO; -using System.Linq.Expressions; using System.Runtime.Serialization; +using CodeBuilder; +using CodeBuilder.Expressions; namespace ObjectSerialization.Builders.Types { - internal class BaseTypeSerializer - { - public static Expression InstantiateNew(Type type) - { - if (type.IsClass && type.GetConstructor(new Type[0]) == null) - return Expression.TypeAs(Expression.Call(typeof(FormatterServices), "GetUninitializedObject", null, Expression.Constant(type)), type); - return Expression.New(type); - } - - protected static Expression CallDeserialize(Expression deserializer, Expression readerObject) - { - return Expression.Call(deserializer, "Invoke", null, readerObject); - } - - protected static Expression CallDeserializeWithConvert(Expression deserializer, Type propertyType, Expression readerObject) - { - return Expression.Convert(Expression.Call(deserializer, "Invoke", null, readerObject), propertyType); - } - - protected static Expression CallSerialize(Expression serializer, Expression value, Expression writerObject) - { - return Expression.Call(serializer, "Invoke", null, writerObject, value); - } - - protected static Expression CallSerializeWithConvert(Expression serializer, Expression value, Type valueType, Expression writerObject) - { - return Expression.Call(serializer, "Invoke", null, writerObject, Expression.Convert(value, valueType)); - } - - protected static Expression CheckNotNull(Expression value, Type valueType) - { - return Expression.ReferenceNotEqual(value, Expression.Constant(null, valueType)); - } - - protected static Expression GetActualValueType(Expression value) - { - return Expression.Call(Expression.TypeAs(value, typeof(object)), "GetType", null); - } - - protected static Expression GetDeserializer(Expression type) - { - return Expression.Call(typeof(TSerializerFactory), "GetDeserializer", null, type); - } - - protected static Expression GetDeserializer(Type type) - { - return Expression.Call(typeof(TSerializerFactory), "GetDeserializer", new[] { type }); - } - - protected static Expression GetReadExpression(string method, Expression reader) - { - return Expression.Call(reader, method, new Type[0]); - } - - protected static Expression GetSerializer(Expression type) - { - return Expression.Call(typeof(TSerializerFactory), "GetSerializer", null, type); - } - - protected static Expression GetSerializer(Type type) - { - return Expression.Call(typeof(TSerializerFactory), "GetSerializer", new[] { type }); - } - - protected static Expression GetWriteExpression(Expression valueExpression, Expression writer) - { - return Expression.Call(writer, "Write", null, valueExpression); - } - - protected static Expression ReloadType(Expression readerObject) - { - return GetReadExpression("ReadString", readerObject); - } - - protected static Expression WriteObjectType(Expression value, Expression objectWriter) - { - Expression valueType = GetActualValueType(value); - MemberExpression typeFullName = Expression.Property(valueType, "FullName"); - return GetWriteExpression(typeFullName, objectWriter); - } - - protected Expression GetDirectDeserializer(Type builderType, Type valueType) - { - return Expression.Property(null, builderType.MakeGenericType(valueType), "DeserializeFn"); - } - - protected Expression GetDirectSerializer(Type builderType, Type valueType) - { - return Expression.Property(null, builderType.MakeGenericType(valueType), "SerializeFn"); - } - - protected static Type GetWriteSerializerDelegateType(Type type) - { - return typeof(Action<,>).MakeGenericType(typeof(BinaryWriter), type); - } - - protected static Type GetReadSerializerDelegateType(Type type) - { - return typeof(Func<,>).MakeGenericType(typeof(BinaryReader), type); - } - } + internal class BaseTypeSerializer + { + public static Expression InstantiateNew(Type type) + { + if (type.IsClass && type.GetConstructor(new Type[0]) == null) + return Expr.Convert(Expr.Call(typeof(FormatterServices), "GetUninitializedObject", Expr.Constant(type)), type); + return Expr.New(type); + } + + protected static Expression CallDeserialize(Expression deserializer, Expression readerObject) + { + return Expr.Call(deserializer, "Invoke", readerObject); + } + + protected static Expression CallDeserializeWithConvert(Expression deserializer, Type propertyType, Expression readerObject) + { + return Expr.Convert(Expr.Call(deserializer, "Invoke", readerObject), propertyType); + } + + protected static Expression CallSerialize(Expression serializer, Expression value, Expression writerObject) + { + return Expr.Call(serializer, "Invoke", writerObject, value); + } + + protected static Expression CallSerializeWithConvert(Expression serializer, Expression value, Type valueType, Expression writerObject) + { + return Expr.Call(serializer, "Invoke", writerObject, Expr.Convert(value, valueType)); + } + + protected static Expression CheckNotNull(Expression value, Type valueType) + { + //return Expr.ReferenceNotEqual(value, Expression.Constant(null, valueType)); + if (!valueType.IsClass && !valueType.IsInterface) throw new ArgumentException("Expected class type, got: " + valueType); + return Expr.IfThenElse(value, Expr.Constant(true), Expr.Constant(false)); + } + + protected static Expression GetActualValueType(Expression value) + { + return Expr.Call(Expr.Convert(value, typeof(object)), "GetType"); //TODO: optimize? + } + + protected static Expression GetDeserializer(Expression type) + { + return Expr.Call(typeof(TSerializerFactory), "GetDeserializer", type); + } + + protected static Expression GetDeserializer(Type type) + { + return Expr.Call(typeof(TSerializerFactory), "GetDeserializer", new[] { type }); + } + + protected static Expression GetReadExpression(string method, Expression reader) + { + return Expr.Call(reader, method); + } + + protected static Expression GetSerializer(Expression type) + { + return Expr.Call(typeof(TSerializerFactory), "GetSerializer", type); + } + + protected static Expression GetSerializer(Type type) + { + return Expr.Call(typeof(TSerializerFactory), "GetSerializer", new[] { type }); + } + + protected static Expression GetWriteExpression(Expression valueExpression, Expression writer) + { + return Expr.Call(writer, "Write", valueExpression); + } + + protected static Expression ReloadType(Expression readerObject) + { + return GetReadExpression("ReadString", readerObject); + } + + protected static Expression WriteObjectType(Expression value, Expression objectWriter) + { + Expression valueType = GetActualValueType(value); + var typeFullName = Expr.ReadProperty(valueType, typeof(Type).GetProperty("FullName")); + return GetWriteExpression(typeFullName, objectWriter); + } + + protected Expression GetDirectDeserializer(Type builderType, Type valueType) + { + return Expr.ReadProperty(builderType.MakeGenericType(valueType).GetProperty("DeserializeFn")); + } + + protected Expression GetDirectSerializer(Type builderType, Type valueType) + { + return Expr.ReadProperty(builderType.MakeGenericType(valueType).GetProperty("SerializeFn")); + } + + protected static Type GetWriteSerializerDelegateType(Type type) + { + return typeof(Action<,>).MakeGenericType(typeof(BinaryWriter), type); + } + + protected static Type GetReadSerializerDelegateType(Type type) + { + return typeof(Func<,>).MakeGenericType(typeof(BinaryReader), type); + } + } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs b/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs index b15b470..9caee3c 100644 --- a/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ClassTypeSerializer.cs @@ -1,5 +1,6 @@ using System; -using System.Linq.Expressions; +using CodeBuilder; +using CodeBuilder.Expressions; using ObjectSerialization.Types; namespace ObjectSerialization.Builders.Types @@ -35,19 +36,19 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp Expression checkNotNull = CheckNotNull(value, valueType); - BlockExpression serializeClass = Expression.Block( - GetWriteExpression(Expression.Constant((byte)1), writerObject), + BlockExpression serializeClass = Expr.Block( + GetWriteExpression(Expr.Constant((byte)1), writerObject), CallSerialize(GetDirectSerializer(typeof(TypeMembersSerializerBuilder<>), valueType), value, writerObject)); - BlockExpression serializePolymorphicClass = Expression.Block( - GetWriteExpression(Expression.Constant((byte)2), writerObject), + BlockExpression serializePolymorphicClass = Expr.Block( + GetWriteExpression(Expr.Constant((byte)2), writerObject), CallSerialize(GetSerializerField(WriteTypeInfo(writerObject, value)), value, writerObject)); Expression serializationExpression = GetSerializationExpression(value, valueType, serializeClass, serializePolymorphicClass); - return Expression.IfThenElse(checkNotNull, + return Expr.IfThenElse(checkNotNull, serializationExpression, - GetWriteExpression(Expression.Constant((byte)0), writerObject)); + GetWriteExpression(Expr.Constant((byte)0), writerObject)); } @@ -61,30 +62,30 @@ public Expression Read(Expression readerObject, Type expectedValueType) ? TypeMembersSerializerBuilder.DeserializeFn.Invoke(r) :TypeInfoWriter.ReadInfo(r).Deserializer.Invoke(r));*/ - ParameterExpression flag = Expression.Variable(typeof(byte), "b"); - BinaryExpression readFlag = Expression.Assign(flag, GetReadExpression("ReadByte", readerObject)); + var flag = Expr.LocalVariable(typeof(byte), "b"); + var readFlag = Expr.DeclareLocal(flag, GetReadExpression("ReadByte", readerObject)); Expression deserializeClass = CallDeserialize(GetDirectDeserializer(typeof(TypeMembersSerializerBuilder<>), expectedValueType), readerObject); Expression deserializePolymorphic = CallDeserializeWithConvert(GetDeserializerField(ReadTypeInfo(readerObject)), expectedValueType, readerObject); - ConditionalExpression deserialization = Expression.Condition( - Expression.Equal(flag, Expression.Constant((byte)0)), - Expression.Constant(null, expectedValueType), - GetDeserializationExpression(flag,expectedValueType, deserializeClass, deserializePolymorphic)); + var deserialization = Expr.IfThenElse( + Expr.ReadLocal(flag), + GetDeserializationExpression(Expr.ReadLocal(flag), expectedValueType, deserializeClass, deserializePolymorphic), + Expr.Null(expectedValueType)); - return Expression.Block(new[] { flag }, readFlag, deserialization); + return Expr.ValueBlock(expectedValueType, readFlag, deserialization); } #endregion - private static Expression GetDeserializationExpression(ParameterExpression flag, Type expectedValueType, Expression deserializeClass, Expression deserializePolymorphic) + private static Expression GetDeserializationExpression(Expression flag, Type expectedValueType, Expression deserializeClass, Expression deserializePolymorphic) { if (expectedValueType.IsSealed) return deserializeClass; if (IsPurePolymorphic(expectedValueType)) return deserializePolymorphic; - return Expression.Condition( - Expression.Equal(flag, Expression.Constant((byte)1)), + return Expr.IfThenElse( + Expr.Equal(flag, Expr.Constant((byte)1)), deserializeClass, deserializePolymorphic); } @@ -97,8 +98,8 @@ private static Expression GetSerializationExpression(Expression value, Type valu if (IsPurePolymorphic(valueType)) return serializePolymorphicClass; - return Expression.IfThenElse( - Expression.Equal(GetActualValueType(value), Expression.Constant(valueType)), + return Expr.IfThenElse( + Expr.Equal(GetActualValueType(value), Expr.Constant(valueType)), serializeClass, serializePolymorphicClass ); @@ -111,22 +112,22 @@ private static bool IsPurePolymorphic(Type valueType) private Expression GetDeserializerField(Expression typeInfo) { - return Expression.Field(typeInfo, "Deserializer"); + return Expr.ReadField(typeInfo, "Deserializer"); } private Expression GetSerializerField(Expression typeInfo) { - return Expression.Field(typeInfo, "Serializer"); + return Expr.ReadField(typeInfo, "Serializer"); } - private MethodCallExpression ReadTypeInfo(Expression readerObject) + private CallExpression ReadTypeInfo(Expression readerObject) { - return Expression.Call(typeof(TypeInfoWriter), "ReadInfo", null, readerObject); + return Expr.Call(typeof(TypeInfoWriter), "ReadInfo", readerObject); } private Expression WriteTypeInfo(Expression writerObject, Expression value) { - return Expression.Call(typeof(TypeInfoWriter), "WriteInfo", null, writerObject, GetActualValueType(value)); + return Expr.Call(typeof(TypeInfoWriter), "WriteInfo", writerObject, GetActualValueType(value)); } } } \ No newline at end of file diff --git a/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs b/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs index 05aed91..264cf4f 100644 --- a/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/CollectionTypeSerializer.cs @@ -1,9 +1,9 @@ using System; using System.Collections; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Linq.Expressions; +using CodeBuilder; +using CodeBuilder.Expressions; using ObjectSerialization.Factories; namespace ObjectSerialization.Builders.Types @@ -44,11 +44,11 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp Expression checkNotNull = CheckNotNull(value, valueType); - BlockExpression collectionWrite = Expression.Block( - GetWriteExpression(Expression.Property(value, "Count"), writerObject), + BlockExpression collectionWrite = Expr.Block( + GetWriteExpression(Expr.ReadProperty(value, "Count"), writerObject), CreateWriteLoop(writerObject, value, valueType)); - return Expression.IfThenElse(checkNotNull, collectionWrite, GetWriteExpression(Expression.Constant(-1), writerObject)); + return Expr.IfThenElse(checkNotNull, collectionWrite, GetWriteExpression(Expr.Constant(-1), writerObject)); } public Expression Read(Expression readerObject, Type expectedValueType) @@ -64,15 +64,16 @@ public Expression Read(Expression readerObject, Type expectedValueType) v.Add(s.Invoke(r)); return v;*/ - ParameterExpression count = Expression.Variable(typeof(int), "c"); - BinaryExpression countRead = Expression.Assign(count, GetReadExpression("ReadInt32", readerObject)); + var count = Expr.LocalVariable(typeof(int), "c"); + var countRead = Expr.DeclareLocal(count, GetReadExpression("ReadInt32", readerObject)); - BlockExpression expression = Expression.Block(new[] { count }, + var expression = Expr.ValueBlock( + expectedValueType, countRead, - Expression.Condition( - Expression.Equal(count, Expression.Constant(-1)), - Expression.Constant(null, expectedValueType), - CreateReadLoop(readerObject, expectedValueType, count))); + Expr.IfThenElse( + Expr.Equal(Expr.ReadLocal(count), Expr.Constant(-1)), + Expr.Null(expectedValueType), + CreateReadLoop(readerObject, expectedValueType, Expr.ReadLocal(count)))); return expression; } @@ -89,26 +90,25 @@ private static Type GetCollectionType(Type type) return type.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollection<>)); } - private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, ParameterExpression count) + private Expression CreateReadLoop(Expression readerObject, Type expectedValueType, Expression count) { - ParameterExpression index = Expression.Parameter(typeof(int), "i"); - ParameterExpression deserializer = Expression.Parameter(GetReadSerializerDelegateType(GetCollectionItemType(expectedValueType)), "s"); - ParameterExpression result = Expression.Parameter(expectedValueType, "v"); - LabelTarget loopEndLabel = Expression.Label(expectedValueType); - - BlockExpression forLoop = Expression.Block( - new[] { index, result, deserializer }, - Expression.Assign(result, InstantiateNew(expectedValueType)), - Expression.Assign(index, Expression.Constant(0, typeof(int))), - Expression.Assign(deserializer, GetDeserializer(GetCollectionItemType(expectedValueType))), - Expression.Loop( - Expression.IfThenElse( - Expression.LessThan(index, count), - Expression.Block( - Expression.Call(Expression.TypeAs(result, GetCollectionType(expectedValueType)), "Add", null, CallDeserialize(deserializer, readerObject)), - Expression.PreIncrementAssign(index)), - Expression.Break(loopEndLabel, result)), - loopEndLabel)); + var index = Expr.LocalVariable(typeof(int), "i"); + var deserializer = Expr.LocalVariable(GetReadSerializerDelegateType(GetCollectionItemType(expectedValueType)), "s"); + var result = Expr.LocalVariable(expectedValueType, "v"); + + var forLoop = Expr.ValueBlock( + expectedValueType, + Expr.DeclareLocal(result, InstantiateNew(expectedValueType)), + Expr.DeclareLocal(index, Expr.Constant(0)), + Expr.DeclareLocal(deserializer, GetDeserializer(GetCollectionItemType(expectedValueType))), + Expr.Loop( + Expr.IfThenElse( + Expr.Less(Expr.ReadLocal(index), count), + Expr.Block( + Expr.Call(Expr.Convert(Expr.ReadLocal(result), GetCollectionType(expectedValueType)), "Add", CallDeserialize(Expr.ReadLocal(deserializer), readerObject)), + Expr.WriteLocal(index,Expr.Add(Expr.ReadLocal(index),Expr.Constant(1)))), + Expr.LoopBreak())), + Expr.ReadLocal(result)); return forLoop; } @@ -116,22 +116,19 @@ private Expression CreateReadLoop(Expression readerObject, Type expectedValueTyp private Expression CreateWriteLoop(Expression writerObject, Expression value, Type valueType) { Type enumeratorType = GetEnumeratorType(valueType); - ParameterExpression enumerator = Expression.Parameter(enumeratorType, "e"); - ParameterExpression serializer = Expression.Parameter(GetWriteSerializerDelegateType(GetCollectionItemType(valueType)), "s"); - LabelTarget loopEndLabel = Expression.Label(); - - return Expression.Block( - new[] { enumerator, serializer }, - Expression.Assign(serializer, GetSerializer(GetCollectionItemType(valueType))), - Expression.Assign(enumerator, Expression.Convert(Expression.Call(value, "GetEnumerator", null), enumeratorType)), - Expression.TryFinally( - Expression.Loop( - Expression.IfThenElse( - Expression.Call(Expression.TypeAs(enumerator, typeof(IEnumerator)), "MoveNext", null), - CallSerialize(serializer, Expression.Property(enumerator, "Current"), writerObject), - Expression.Break(loopEndLabel)), - loopEndLabel), - Expression.Call(Expression.TypeAs(enumerator, typeof(IDisposable)), "Dispose", null))); + var enumerator = Expr.LocalVariable(enumeratorType, "e"); + var serializer = Expr.LocalVariable(GetWriteSerializerDelegateType(GetCollectionItemType(valueType)), "s"); + + return Expr.Block( + Expr.DeclareLocal(serializer, GetSerializer(GetCollectionItemType(valueType))), + Expr.DeclareLocal(enumerator, Expr.Convert(Expr.Call(value, "GetEnumerator"), enumeratorType)), + Expr.TryFinally( + Expr.Loop( + Expr.IfThenElse( + Expr.Call(Expr.Convert(Expr.ReadLocal(enumerator), typeof(IEnumerator)), "MoveNext"), + CallSerialize(Expr.ReadLocal(serializer), Expr.ReadProperty(Expr.ReadLocal(enumerator), "Current"), writerObject), + Expr.LoopBreak())), + Expr.Call(Expr.Convert(Expr.ReadLocal(enumerator), typeof(IDisposable)), "Dispose"))); } private Type GetEnumeratorType(Type collectionType) diff --git a/ObjectSerialization/Builders/Types/ISerializer.cs b/ObjectSerialization/Builders/Types/ISerializer.cs index fc2a355..a550acf 100644 --- a/ObjectSerialization/Builders/Types/ISerializer.cs +++ b/ObjectSerialization/Builders/Types/ISerializer.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using CodeBuilder.Expressions; namespace ObjectSerialization.Builders.Types { diff --git a/ObjectSerialization/Builders/Types/PredefinedTypeSerializer.cs b/ObjectSerialization/Builders/Types/PredefinedTypeSerializer.cs index 25caad7..da8044f 100644 --- a/ObjectSerialization/Builders/Types/PredefinedTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/PredefinedTypeSerializer.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; +using CodeBuilder.Expressions; namespace ObjectSerialization.Builders.Types { diff --git a/ObjectSerialization/Builders/Types/StringTypeSerializer.cs b/ObjectSerialization/Builders/Types/StringTypeSerializer.cs index c87a4a1..78bb535 100644 --- a/ObjectSerialization/Builders/Types/StringTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/StringTypeSerializer.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; +using CodeBuilder; +using CodeBuilder.Expressions; namespace ObjectSerialization.Builders.Types { @@ -26,9 +27,9 @@ public Expression Write(Expression writerObject, Expression value, Type valueTyp Expression notNull = CheckNotNull(value, valueType); - return Expression.Block( + return Expr.Block( GetWriteExpression(notNull, writerObject), - Expression.IfThen( + Expr.IfThen( notNull, GetWriteExpression(value, writerObject))); } @@ -39,10 +40,10 @@ public Expression Read(Expression readerObject, Type expectedValueType) BinaryReader r; return r.ReadBoolean()?r.ReadString():null;*/ - return Expression.Condition( + return Expr.IfThenElse( GetReadExpression("ReadBoolean", readerObject), GetReadExpression("Read" + expectedValueType.Name, readerObject), - Expression.Constant(null, expectedValueType)); + Expr.Null(expectedValueType)); } #endregion diff --git a/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs b/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs index 912b18e..62237d6 100644 --- a/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs +++ b/ObjectSerialization/Builders/Types/ValueTypeSerializer.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using CodeBuilder.Expressions; namespace ObjectSerialization.Builders.Types { diff --git a/ObjectSerialization/ObjectSerialization.csproj b/ObjectSerialization/ObjectSerialization.csproj index 8d00879..53b626b 100644 --- a/ObjectSerialization/ObjectSerialization.csproj +++ b/ObjectSerialization/ObjectSerialization.csproj @@ -55,6 +55,12 @@ + + + {22256B91-E772-40A0-BED3-AA6E10EEF1E5} + CodeBuilder + +