PageRenderTime 46ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/FluentSerializer/Generators/ICollectionGenerator.cs

http://fluentserializer.codeplex.com
C# | 235 lines | 160 code | 53 blank | 22 comment | 47 complexity | d13088f20dc7272ee198d89a7ec465f7 MD5 | raw file
  1. // -----------------------------------------------------------------------
  2. // <copyright file="ICollectionGenerator.cs" company="none">
  3. // Copyright (c) 2012 M. Alberti, xanatos(at)live.it
  4. // Distributed under the MIT/X11 software license, see the accompanying
  5. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  6. // </copyright>
  7. // -----------------------------------------------------------------------
  8. namespace FluentSerializer.Generators
  9. {
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Linq.Expressions;
  14. using System.Reflection;
  15. using FluentStatement;
  16. using FluentStatement.Utilities;
  17. /// <summary>
  18. ///
  19. /// </summary>
  20. public static class ICollectionGenerator
  21. {
  22. /// <summary>
  23. ///
  24. /// </summary>
  25. /// <param name="serializer"></param>
  26. /// <param name="parametersType"></param>
  27. /// <param name="type"></param>
  28. /// <param name="helper"></param>
  29. /// <returns></returns>
  30. public static Descriptor BuildSerializer(Serializer serializer, Type parametersType, Type type, Type helper)
  31. {
  32. bool isUniversal = true;
  33. Type decoratedTypeWithHelper = helper.IsGenericTypeDefinition ? helper.MakeGenericType(type) : helper;
  34. Type decoratedType = type;
  35. Type realType = Serializer.UndecorateType(type);
  36. Type[] temp = decoratedType.GetInterfaces(typeof(ICollection<>));
  37. if (temp.Length != 1)
  38. {
  39. throw new NotSupportedException();
  40. }
  41. Type decoratedInterfaceType = temp[0];
  42. temp = realType.GetInterfaces(typeof(ICollection<>));
  43. if (temp.Length != 1)
  44. {
  45. throw new NotSupportedException();
  46. }
  47. Type realInterfaceType = temp[0];
  48. InterfaceMapping mapping = realType.IsInterface ? default(InterfaceMapping) : realType.GetInterfaceMap(realInterfaceType);
  49. Type decoratedSubItemType = decoratedInterfaceType.GetGenericArguments()[0];
  50. Type realSubItemType = realInterfaceType.GetGenericArguments()[0];
  51. ParameterExpression item = Expression.Parameter(realType);
  52. ParameterExpression parameters = parametersType != null ? Expression.Parameter(parametersType) : null;
  53. ParameterExpression subItem = Expression.Variable(realSubItemType);
  54. Descriptor subItemDescriptor = Serializer.GetSerializer(serializer, realSubItemType, decoratedSubItemType, helper);
  55. isUniversal &= subItemDescriptor.IsUniversal;
  56. PropertyInfo count = (from p in realType.GetVisibleProperties()
  57. where p.Name == "Count"
  58. let get = p.GetGetMethod(false)
  59. where get != null && !get.IsStatic && p.GetIndexParameters().Length == 0
  60. select p).FirstOrDefault();
  61. MemberExpression count2;
  62. if (count != null)
  63. {
  64. count2 = Expression.Property(item, count);
  65. }
  66. else
  67. {
  68. MethodInfo count3 = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "get_Count")];
  69. count2 = Expression.Property(item, count3);
  70. }
  71. ConstructorInfo constructor = decoratedTypeWithHelper.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
  72. var helper2 = (ICollectionHelper)constructor.Invoke(null);
  73. isUniversal &= helper2.IsUniversal;
  74. LambdaExpression disposeExpression;
  75. LambdaExpression deserializeExpression;
  76. LambdaExpression serializeExpression;
  77. LambdaExpression sizeExpression;
  78. /***/
  79. {
  80. var block = new List<Expression>();
  81. if (typeof(IDisposable).IsAssignableFrom(realType))
  82. {
  83. LambdaExpression realTypeDispose = Serializer.GetDisposeExpression(realType);
  84. block.Add(Serializer.MakeFromLambda(realTypeDispose, false, item));
  85. }
  86. if (subItemDescriptor.DeserializationHandling.HasFlag(DeserializationHandling.RequireDispose))
  87. {
  88. block.Add(ExpressionEx.ForEach(item, subItemDescriptor.DeserializeExpression, Expression.Label()));
  89. }
  90. disposeExpression = block.Count == 0 ? null : Serializer.MakeLambda(Expression.Block(block), false, item);
  91. }
  92. /***/
  93. {
  94. MethodInfo[] methods = realType.GetVisibleMethods();
  95. MethodInfo clear = (from p in methods
  96. where p.Name == "Clear" && !p.IsStatic && !p.IsGenericMethod && p.ReturnType == typeof(void) && p.GetParameters().Length == 0
  97. select p).FirstOrDefault();
  98. if (clear == null)
  99. {
  100. clear = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "Clear")];
  101. }
  102. MethodInfo add = (from p in methods
  103. where p.Name == "Add" && !p.IsStatic && !p.IsGenericMethod && p.ReturnType == typeof(void)
  104. let pars = p.GetParameters()
  105. where pars.Length == 1 && pars[0].ParameterType == realSubItemType
  106. select p).FirstOrDefault();
  107. if (add == null)
  108. {
  109. add = mapping.TargetMethods[Array.FindIndex(mapping.InterfaceMethods, p => p.Name == "Add")];
  110. }
  111. var block = new List<Expression>();
  112. ParameterExpression size = Expression.Variable(typeof(int));
  113. if (subItemDescriptor.DeserializationHandling.HasFlag(DeserializationHandling.RequireDispose))
  114. {
  115. block.Add(ExpressionEx.ForEach(item, subItemDescriptor.DeserializeExpression, Expression.Label()));
  116. }
  117. block.Add(Expression.Call(item, clear));
  118. block.Add(Expression.Assign(size, helper2.DeserializeLength(Serializer.ReaderExpression, count2) ?? count2));
  119. Expression subItemDeserialize = Expression.Call(item, add, Serializer.MakeFromLambda(subItemDescriptor.DeserializeExpression, subItemDescriptor.IsUniversal, Serializer.ReaderExpression, subItem, parameters));
  120. if (!(subItemDescriptor.DefaultExpression is DefaultExpression))
  121. {
  122. subItemDeserialize = Expression.Block(
  123. Expression.Assign(subItem, subItemDescriptor.DefaultExpression),
  124. subItemDeserialize);
  125. }
  126. ForExpression @for = ExpressionEx.For(Expression.PostDecrementAssign(size), Expression.GreaterThan(size, Serializer.Zero), subItemDeserialize, Expression.Label());
  127. block.Add(@for);
  128. block.Add(item);
  129. BlockExpression expression = Expression.Block(new[] { size, subItem }, block);
  130. deserializeExpression = Serializer.MakeLambda(expression, isUniversal, Serializer.ReaderExpression, item, parameters);
  131. }
  132. /***/
  133. {
  134. var block = new List<Expression>();
  135. Expression sizeSerialize = helper2.SerializeLength(Serializer.WriterExpression, count2);
  136. if (sizeSerialize != null)
  137. {
  138. block.Add(sizeSerialize);
  139. }
  140. Expression subItemSerialize = Serializer.MakeFromLambda(subItemDescriptor.SerializeExpression, subItemDescriptor.IsUniversal, Serializer.WriterExpression, subItem, parameters);
  141. Expression forEach = ExpressionEx.ForEach(item, Expression.Lambda(subItemSerialize, subItem), Expression.Label());
  142. block.Add(forEach);
  143. Expression block2 = block.Count == 1 ? block[0] : Expression.Block(block);
  144. serializeExpression = Serializer.MakeLambda(block2, isUniversal, Serializer.WriterExpression, item, parameters);
  145. }
  146. /***/
  147. {
  148. Expression baseSize = helper2.SizeLength(count2);
  149. if (subItemDescriptor.SizeExpression.Body is ConstantExpression)
  150. {
  151. Expression size = Expression.Multiply(subItemDescriptor.SizeExpression.Body, count2);
  152. if (baseSize != null)
  153. {
  154. size = Expression.Add(baseSize, size);
  155. }
  156. sizeExpression = Serializer.MakeLambda(size, isUniversal, item, parameters);
  157. }
  158. else
  159. {
  160. var block = new List<Expression>();
  161. ParameterExpression size = Expression.Variable(typeof(int));
  162. if (baseSize != null)
  163. {
  164. block.Add(Expression.Assign(size, baseSize));
  165. }
  166. else
  167. {
  168. block.Add(Expression.Assign(size, Serializer.Zero));
  169. }
  170. Expression subItemSize = Serializer.MakeFromLambda(subItemDescriptor.SizeExpression, subItemDescriptor.IsUniversal, subItem, parameters);
  171. ForEachExpression forEach = ExpressionEx.ForEach(item, Expression.Lambda(Expression.AddAssign(size, subItemSize), subItem), Expression.Label());
  172. block.Add(forEach);
  173. block.Add(size);
  174. BlockExpression expression = Expression.Block(new[] { size }, block);
  175. sizeExpression = Serializer.MakeLambda(expression, isUniversal, item, parameters);
  176. }
  177. }
  178. var descriptor = new Descriptor(decoratedTypeWithHelper, isUniversal, deserializeExpression, DeserializationHandling.None, serializeExpression, sizeExpression, disposeExpression);
  179. return descriptor;
  180. }
  181. }
  182. }