/src/MefContrib/Hosting/Conventions/Configuration/ExpressionBuilder.cs

https://github.com/jorgemuza/MefContrib · C# · 154 lines · 107 code · 24 blank · 23 comment · 11 complexity · 36307def19c6b46d837343bb472dff12 MD5 · raw file

  1. namespace MefContrib.Hosting.Conventions.Configuration
  2. {
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Linq.Expressions;
  8. using System.Reflection;
  9. /// <summary>
  10. /// Represents the expression builder.
  11. /// </summary>
  12. public interface IExpressionBuilder
  13. {
  14. /// <summary>
  15. /// Builds the specific instance and assigns values using expressions.
  16. /// </summary>
  17. /// <returns>Initialized instance of an object.</returns>
  18. object Build();
  19. }
  20. /// <summary>
  21. /// Abstract expression builder.
  22. /// </summary>
  23. /// <typeparam name="T">Type of the object to be built.</typeparam>
  24. public abstract class ExpressionBuilder<T> : IExpressionBuilder where T : new()
  25. {
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="ExpressionBuilder{T}"/> class.
  28. /// </summary>
  29. protected ExpressionBuilder()
  30. {
  31. this.MemberValues = new Dictionary<MemberInfo, List<object>>();
  32. }
  33. private IDictionary<MemberInfo, List<object>> MemberValues { get; set; }
  34. /// <summary>
  35. /// Builds the specific instance and assigns values using expressions.
  36. /// </summary>
  37. /// <returns>Initialized instance of an object.</returns>
  38. public object Build()
  39. {
  40. var instance = new T();
  41. foreach (var member in this.MemberValues.Keys)
  42. {
  43. this.SetMemberValue(member, instance);
  44. }
  45. return instance;
  46. }
  47. /// <summary>
  48. /// Assigns given value to a property given by the expression.
  49. /// </summary>
  50. /// <param name="expression">The expression.</param>
  51. /// <param name="value">Value to be assigned to a property represented by the <paramref name="expression"/>.</param>
  52. public void ProvideValueFor(Expression<Func<T, object>> expression, object value)
  53. {
  54. var member =
  55. expression.GetTargetMemberInfo();
  56. if (member == null)
  57. {
  58. throw new InvalidOperationException();
  59. }
  60. if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
  61. {
  62. throw new InvalidOperationException();
  63. }
  64. this.StoreMemberValue(member, value);
  65. }
  66. private static void SetCollectionValue(MemberInfo member, object instance, List<object> value)
  67. {
  68. const BindingFlags bindingFlags =
  69. BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod;
  70. object collection = null;
  71. switch (member.MemberType)
  72. {
  73. case MemberTypes.Field:
  74. collection = ((FieldInfo)member).GetValue(instance);
  75. break;
  76. case MemberTypes.Property:
  77. collection = ((PropertyInfo)member).GetValue(instance, null);
  78. break;
  79. }
  80. var method = collection
  81. .GetType()
  82. .GetMethod("Add", bindingFlags);
  83. value.ForEach(x => method.Invoke(collection, bindingFlags, null, new[] { x }, null));
  84. }
  85. private void SetMemberValue(MemberInfo member, object instance)
  86. {
  87. var value =
  88. this.MemberValues[member];
  89. var memberType =
  90. member.GetContractMember();
  91. if (memberType.IsCollection())
  92. {
  93. SetCollectionValue(member, instance, value);
  94. }
  95. else
  96. {
  97. SetSingleValue(member, instance, value);
  98. }
  99. }
  100. private static void SetSingleValue(MemberInfo member, object instance, IEnumerable<object> value)
  101. {
  102. switch (member.MemberType)
  103. {
  104. case MemberTypes.Field:
  105. ((FieldInfo)member).SetValue(instance, value.First());
  106. break;
  107. case MemberTypes.Property:
  108. ((PropertyInfo)member).SetValue(instance, value.First(), null);
  109. break;
  110. }
  111. }
  112. private void StoreMemberValue(MemberInfo member, object value)
  113. {
  114. if (!this.MemberValues.ContainsKey(member))
  115. {
  116. this.MemberValues.Add(member, new List<object>());
  117. }
  118. var valueList =
  119. this.MemberValues[member];
  120. if (value.GetType().IsEnumerable())
  121. {
  122. valueList.AddRange(((IEnumerable)value).Cast<object>());
  123. }
  124. else
  125. {
  126. valueList.Add(value);
  127. }
  128. }
  129. }
  130. }