Loom.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. namespace Quadarax.Foundation.Core.Mapper
  5. {
  6. /// <summary>
  7. /// Lightweight Object-to-Object Mapper.
  8. /// </summary>
  9. public class Loom
  10. {
  11. /// <summary>
  12. /// Defines a new mapping function using a configuration-driven builder.
  13. /// </summary>
  14. /// <typeparam name="TFrom">The source type.</typeparam>
  15. /// <typeparam name="TTo">The destination type.</typeparam>
  16. /// <returns></returns>
  17. public LoomBuilder<TFrom, TTo> Define<TFrom, TTo>()
  18. where TFrom : class
  19. where TTo : class, new()
  20. {
  21. return new LoomBuilder<TFrom, TTo>(this);
  22. }
  23. /// <summary>
  24. /// Defines a new mapping function.
  25. /// </summary>
  26. /// <typeparam name="TFrom">The source type.</typeparam>
  27. /// <typeparam name="TTo">The destination type.</typeparam>
  28. /// <param name="map">The mapping function.</param>
  29. public void Define<TFrom, TTo>(Action<TFrom, TTo> map)
  30. {
  31. Dictionary<Type, Delegate> inner;
  32. if (!_maps.TryGetValue(typeof(TFrom), out inner))
  33. {
  34. inner = new Dictionary<Type, Delegate>();
  35. _maps[typeof(TFrom)] = inner;
  36. }
  37. inner[typeof(TTo)] = map;
  38. }
  39. /// <summary>
  40. /// Finds a mapping function.
  41. /// </summary>
  42. /// <typeparam name="TFrom">The source type.</typeparam>
  43. /// <typeparam name="TTo">The destination type.</typeparam>
  44. /// <returns>The mapping function for the given combination of types or a null reference when not defined.</returns>
  45. public Action<TFrom, TTo> Find<TFrom, TTo>()
  46. {
  47. Dictionary<Type, Delegate> inner;
  48. if (!_maps.TryGetValue(typeof(TFrom), out inner)) return null;
  49. Delegate map;
  50. if (!inner.TryGetValue(typeof(TTo), out map)) return null;
  51. return (Action<TFrom, TTo>) map;
  52. }
  53. /// <summary>
  54. /// Updates the destination object from the source using a mapping function.
  55. /// </summary>
  56. /// <typeparam name="TFrom">The source type.</typeparam>
  57. /// <typeparam name="TTo">The destination type.</typeparam>
  58. /// <param name="from">The source object.</param>
  59. /// <param name="to">The destination object.</param>
  60. public void Update<TFrom, TTo>(TFrom from, TTo to)
  61. where TFrom : class
  62. where TTo : class
  63. {
  64. if (from == null) throw new ArgumentNullException("from");
  65. if (to == null) throw new ArgumentNullException("to");
  66. Find<TFrom, TTo>()(from, to);
  67. }
  68. /// <summary>
  69. /// Creates a destination object from the source using a mapping function.
  70. /// </summary>
  71. /// <typeparam name="TFrom">The source type.</typeparam>
  72. /// <typeparam name="TTo">The destination type.</typeparam>
  73. /// <param name="from">The source object.</param>
  74. /// <returns>The destination object or a null reference in case <paramref name="from"/> is a null reference, too.</returns>
  75. public TTo Map<TFrom, TTo>(TFrom from)
  76. where TFrom : class
  77. where TTo : class, new()
  78. {
  79. if (from == null) return null;
  80. var to = new TTo();
  81. Find<TFrom, TTo>()(from, to);
  82. return to;
  83. }
  84. /// <summary>
  85. /// Creates a list of destination objects from source objects using a mapping function.
  86. /// </summary>
  87. /// <typeparam name="TFrom">The source type.</typeparam>
  88. /// <typeparam name="TTo">The destination type.</typeparam>
  89. /// <param name="from">The source objects.</param>
  90. /// <returns>The destination objects.</returns>
  91. public List<TTo> Map<TFrom, TTo>(IEnumerable<TFrom> from)
  92. where TFrom : class
  93. where TTo : class, new()
  94. {
  95. if (from == null) return null;
  96. var map = Find<TFrom, TTo>();
  97. return new List<TTo>(from.Select(f => {
  98. var to = new TTo();
  99. map(f, to);
  100. return to;
  101. }));
  102. }
  103. /// <summary>
  104. /// Creates a list of destination objects from source objects using a mapping function.
  105. /// </summary>
  106. /// <typeparam name="TFrom">The source type.</typeparam>
  107. /// <typeparam name="TTo">The destination type.</typeparam>
  108. /// <param name="from">The source objects.</param>
  109. /// <returns>The destination objects.</returns>
  110. public List<TTo> MapList<TFrom, TTo>(IEnumerable<TFrom> from)
  111. where TFrom : class
  112. where TTo : class, new()
  113. {
  114. if (from == null) return null;
  115. var map = Find<TFrom, TTo>();
  116. return from.Select(f => New(map, f)).ToList();
  117. }
  118. /// <summary>
  119. /// Creates a list of destination objects from source objects using a mapping function.
  120. /// </summary>
  121. /// <typeparam name="TFrom">The source type.</typeparam>
  122. /// <typeparam name="TTo">The destination type.</typeparam>
  123. /// <param name="from">The source objects.</param>
  124. /// <returns>The destination objects.</returns>
  125. public List<TTo> MapList<TFrom, TTo>(IQueryable<TFrom> from)
  126. where TFrom : class
  127. where TTo : class, new()
  128. {
  129. if (from == null) return null;
  130. var map = Find<TFrom, TTo>();
  131. return from.Select(f => New(map, f)).ToList();
  132. }
  133. #region ------ Internals ------------------------------------------------------------------
  134. private TTo New<TFrom, TTo>(Action<TFrom, TTo> map, TFrom f)
  135. where TFrom : class
  136. where TTo : class, new()
  137. {
  138. var to = new TTo();
  139. map(f, to);
  140. return to;
  141. }
  142. /// <summary>
  143. /// Repository of all known mapping functions.
  144. /// </summary>
  145. private readonly Dictionary<Type, Dictionary<Type, Delegate>> _maps = new Dictionary<Type, Dictionary<Type, Delegate>>();
  146. #endregion
  147. }
  148. }