From e06157d1f82b863ad50a812a9651b8678457fa45 Mon Sep 17 00:00:00 2001 From: Suremaker Date: Sun, 6 Apr 2014 16:11:49 +0100 Subject: [PATCH] + 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)) }; } }