/FluentSerializer/Generators/ICollectionGenerator.cs
C# | 235 lines | 160 code | 53 blank | 22 comment | 47 complexity | d13088f20dc7272ee198d89a7ec465f7 MD5 | raw file
- // -----------------------------------------------------------------------
- // <copyright file="ICollectionGenerator.cs" company="none">
- // Copyright (c) 2012 M. Alberti, xanatos(at)live.it
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- // </copyright>
- // -----------------------------------------------------------------------
-
- namespace FluentSerializer.Generators
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using FluentStatement;
- using FluentStatement.Utilities;
-
- /// <summary>
- ///
- /// </summary>
- public static class ICollectionGenerator
- {
- /// <summary>
- ///
- /// </summary>
- /// <param name="serializer"></param>
- /// <param name="parametersType"></param>
- /// <param name="type"></param>
- /// <param name="helper"></param>
- /// <returns></returns>
- public static Descriptor BuildSerializer(Serializer serializer, Type parametersType, Type type, Type helper)
- {
- bool isUniversal = true;
-
- Type decoratedTypeWithHelper = helper.IsGenericTypeDefinition ? helper.MakeGenericType(type) : helper;
- Type decoratedType = type;
- Type realType = Serializer.UndecorateType(type);
-
- Type[] temp = decoratedType.GetInterfaces(typeof(ICollection<>));
-
- if (temp.Length != 1)
- {
- throw new NotSupportedException();
- }
-
- Type decoratedInterfaceType = temp[0];
-
- temp = realType.GetInterfaces(typeof(ICollection<>));
-
- if (temp.Length != 1)
- {
- throw new NotSupportedException();
- }
-
- Type realInterfaceType = temp[0];
-
- InterfaceMapping mapping = realType.IsInterface ? default(InterfaceMapping) : realType.GetInterfaceMap(realInterfaceType);
-
- Type decoratedSubItemType = decoratedInterfaceType.GetGenericArguments()[0];
- Type realSubItemType = realInterfaceType.GetGenericArguments()[0];
-
- ParameterExpression item = Expression.Parameter(realType);
- ParameterExpression parameters = parametersType != null ? Expression.Parameter(parametersType) : null;
- ParameterExpression subItem = Expression.Variable(realSubItemType);
-
- Descriptor subItemDescriptor = Serializer.GetSerializer(serializer, realSubItemType, decoratedSubItemType, helper);
- isUniversal &= subItemDescriptor.IsUniversal;
-
- PropertyInfo count = (from p in realType.GetVisibleProperties()
- where p.Name == "Count"
- let get = p.GetGetMethod(false)
- where get != null && !get.IsStatic && p.GetIndexParameters().Length == 0
- select p).FirstOrDefault();
-
- MemberExpression count2;
-
- if (count != null)
- {
- count2 = Expression.Property(item, count);
- }
- else
- {
- MethodInfo count3 = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "get_Count")];
- count2 = Expression.Property(item, count3);
- }
-
- ConstructorInfo constructor = decoratedTypeWithHelper.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
- var helper2 = (ICollectionHelper)constructor.Invoke(null);
- isUniversal &= helper2.IsUniversal;
-
- LambdaExpression disposeExpression;
- LambdaExpression deserializeExpression;
- LambdaExpression serializeExpression;
- LambdaExpression sizeExpression;
-
- /***/
- {
- var block = new List<Expression>();
-
- if (typeof(IDisposable).IsAssignableFrom(realType))
- {
- LambdaExpression realTypeDispose = Serializer.GetDisposeExpression(realType);
- block.Add(Serializer.MakeFromLambda(realTypeDispose, false, item));
- }
-
- if (subItemDescriptor.DeserializationHandling.HasFlag(DeserializationHandling.RequireDispose))
- {
- block.Add(ExpressionEx.ForEach(item, subItemDescriptor.DeserializeExpression, Expression.Label()));
- }
-
- disposeExpression = block.Count == 0 ? null : Serializer.MakeLambda(Expression.Block(block), false, item);
- }
-
- /***/
- {
- MethodInfo[] methods = realType.GetVisibleMethods();
-
- MethodInfo clear = (from p in methods
- where p.Name == "Clear" && !p.IsStatic && !p.IsGenericMethod && p.ReturnType == typeof(void) && p.GetParameters().Length == 0
- select p).FirstOrDefault();
-
- if (clear == null)
- {
- clear = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "Clear")];
- }
-
- MethodInfo add = (from p in methods
- where p.Name == "Add" && !p.IsStatic && !p.IsGenericMethod && p.ReturnType == typeof(void)
- let pars = p.GetParameters()
- where pars.Length == 1 && pars[0].ParameterType == realSubItemType
- select p).FirstOrDefault();
-
- if (add == null)
- {
- add = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "Add")];
- }
-
- var block = new List<Expression>();
-
- ParameterExpression size = Expression.Variable(typeof(int));
-
- if (subItemDescriptor.DeserializationHandling.HasFlag(DeserializationHandling.RequireDispose))
- {
- block.Add(ExpressionEx.ForEach(item, subItemDescriptor.DeserializeExpression, Expression.Label()));
- }
-
- block.Add(Expression.Call(item, clear));
-
- block.Add(Expression.Assign(size, helper2.DeserializeLength(Serializer.ReaderExpression, count2) ?? count2));
-
- Expression subItemDeserialize = Expression.Call(item, add, Serializer.MakeFromLambda(subItemDescriptor.DeserializeExpression, subItemDescriptor.IsUniversal, Serializer.ReaderExpression, subItem, parameters));
-
- if (!(subItemDescriptor.DefaultExpression is DefaultExpression))
- {
- subItemDeserialize = Expression.Block(
- Expression.Assign(subItem, subItemDescriptor.DefaultExpression),
- subItemDeserialize);
- }
-
- ForExpression @for = ExpressionEx.For(Expression.PostDecrementAssign(size), Expression.GreaterThan(size, Serializer.Zero), subItemDeserialize, Expression.Label());
-
- block.Add(@for);
- block.Add(item);
-
- BlockExpression expression = Expression.Block(new[] { size, subItem }, block);
- deserializeExpression = Serializer.MakeLambda(expression, isUniversal, Serializer.ReaderExpression, item, parameters);
- }
-
- /***/
- {
- var block = new List<Expression>();
-
- Expression sizeSerialize = helper2.SerializeLength(Serializer.WriterExpression, count2);
-
- if (sizeSerialize != null)
- {
- block.Add(sizeSerialize);
- }
-
- Expression subItemSerialize = Serializer.MakeFromLambda(subItemDescriptor.SerializeExpression, subItemDescriptor.IsUniversal, Serializer.WriterExpression, subItem, parameters);
- Expression forEach = ExpressionEx.ForEach(item, Expression.Lambda(subItemSerialize, subItem), Expression.Label());
-
- block.Add(forEach);
-
- Expression block2 = block.Count == 1 ? block[0] : Expression.Block(block);
- serializeExpression = Serializer.MakeLambda(block2, isUniversal, Serializer.WriterExpression, item, parameters);
- }
-
- /***/
- {
- Expression baseSize = helper2.SizeLength(count2);
-
- if (subItemDescriptor.SizeExpression.Body is ConstantExpression)
- {
- Expression size = Expression.Multiply(subItemDescriptor.SizeExpression.Body, count2);
-
- if (baseSize != null)
- {
- size = Expression.Add(baseSize, size);
- }
-
- sizeExpression = Serializer.MakeLambda(size, isUniversal, item, parameters);
- }
- else
- {
- var block = new List<Expression>();
-
- ParameterExpression size = Expression.Variable(typeof(int));
-
- if (baseSize != null)
- {
- block.Add(Expression.Assign(size, baseSize));
- }
- else
- {
- block.Add(Expression.Assign(size, Serializer.Zero));
- }
-
- Expression subItemSize = Serializer.MakeFromLambda(subItemDescriptor.SizeExpression, subItemDescriptor.IsUniversal, subItem, parameters);
- ForEachExpression forEach = ExpressionEx.ForEach(item, Expression.Lambda(Expression.AddAssign(size, subItemSize), subItem), Expression.Label());
-
- block.Add(forEach);
- block.Add(size);
-
- BlockExpression expression = Expression.Block(new[] { size }, block);
- sizeExpression = Serializer.MakeLambda(expression, isUniversal, item, parameters);
- }
- }
-
- var descriptor = new Descriptor(decoratedTypeWithHelper, isUniversal, deserializeExpression, DeserializationHandling.None, serializeExpression, sizeExpression, disposeExpression);
- return descriptor;
- }
- }
- }