code_junkie

Lazy loading and lazy execution patterns

Nov 13th, 2011
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.99 KB | None | 0 0
  1. private SomeClass _someProperty;
  2. public SomeClass SomeProperty
  3. {
  4. get
  5. {
  6. if(this._someProperty == null)
  7. {
  8. // run code to populate/instantiate _someProperty
  9. }
  10. return this._someProperty;
  11. }
  12. }
  13.  
  14. /// <summary>
  15. /// A container for an object of type <typeparamref name="T"/> whose value is not known until the <see cref="Value" /> property is accessed.
  16. /// </summary>
  17. /// <typeparam name="T">The type of the underlying object.</typeparam>
  18. public class Lazy<T>
  19. {
  20. /// <summary>
  21. /// A value representing whether the delegates have been invoked.
  22. /// </summary>
  23. private Boolean _wereValueDelegatesInvoked;
  24.  
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="Lazy{T}" /> class with the specified <paramref name="valueDelegates"/>.
  27. /// </summary>
  28. /// <param name="valueDelegates">A list of delegates that can potentially return the value of the underlying object.</param>
  29. public Lazy(params Func<T>[] valueDelegates)
  30. {
  31. this.ValueDelegates = valueDelegates;
  32. }
  33.  
  34. /// <summary>
  35. /// Gets the delegate that returns the value of the underlying object.
  36. /// </summary>
  37. public IEnumerable<Func<T>> ValueDelegates { get; protected set; }
  38.  
  39. private T _value;
  40. /// <summary>
  41. /// Gets the value of the underlying object. If multiple delegates are specified, the first delegate to return a non-default value will be used.
  42. /// </summary>
  43. public T Value
  44. {
  45. get
  46. {
  47. if (!this._wereValueDelegatesInvoked)
  48. {
  49. this._value = this.GetValue();
  50. }
  51. return this._value;
  52. }
  53. }
  54.  
  55. /// <summary>
  56. /// Return the value of the underlying object. If multiple delegates are specified, the first delegate to return a non-default value will be used.
  57. /// </summary>
  58. /// <returns>The value of the underlying object.</returns>
  59. protected T GetValue()
  60. {
  61. T value = default(T);
  62.  
  63. if (this.ValueDelegates != null)
  64. {
  65. foreach (Func<T> valueDelegate in this.ValueDelegates)
  66. {
  67. value = valueDelegate.Invoke();
  68. if (!Lazy<T>.IsNullOrDefault(value)) break;
  69. }
  70. }
  71.  
  72. this._wereValueDelegatesInvoked = true;
  73. return value;
  74. }
  75. }
  76.  
  77. /// <summary>
  78. /// A container for an object of type <typeparamref name="T"/> whose value is not known until the <see cref="Value" /> property is accessed.
  79. /// </summary>
  80. /// <typeparam name="T">The type of the underlying object.</typeparam>
  81. public class Lazy<T>
  82. {
  83. /// <summary>
  84. /// A value representing whether the delegates have been invoked.
  85. /// </summary>
  86. private Boolean _wereValueDelegatesInvoked;
  87.  
  88. /// <summary>
  89. /// Initializes a new instance of the <see cref="Lazy{T}" /> class with the specified <paramref name="valueDelegate"/>.
  90. /// </summary>
  91. /// <param name="valueDelegate">A delegate that returns the value of the underlying object.</param>
  92. public Lazy(Func<T> valueDelegate)
  93. {
  94. this.ValueDelegates = new Func<T>[] { valueDelegate };
  95. }
  96.  
  97. /// <summary>
  98. /// Initializes a new instance of the <see cref="Lazy{T}" /> class with the specified <paramref name="valueDelegates"/>.
  99. /// </summary>
  100. /// <param name="valueDelegates">A list of delegates that can potentially return the value of the underlying object.</param>
  101. public Lazy(IEnumerable<Func<T>> valueDelegates)
  102. {
  103. this.ValueDelegates = valueDelegates;
  104. }
  105.  
  106. /// <summary>
  107. /// Initializes a new instance of the <see cref="Lazy{T}" /> class with the specified <paramref name="valueDelegates"/>.
  108. /// </summary>
  109. /// <param name="valueDelegates">A list of delegates that can potentially return the value of the underlying object.</param>
  110. public Lazy(params Func<T>[] valueDelegates)
  111. {
  112. this.ValueDelegates = valueDelegates;
  113. }
  114.  
  115. public Lazy(T value)
  116. {
  117. this._value = value;
  118. this._wereValueDelegatesInvoked = true;
  119. }
  120.  
  121. /// <summary>
  122. /// Gets the delegate that returns the value of the underlying object.
  123. /// </summary>
  124. public IEnumerable<Func<T>> ValueDelegates { get; protected set; }
  125.  
  126. private T _value;
  127. /// <summary>
  128. /// Gets the value of the underlying object. If multiple delegates are specified, the first delegate to return a non-default value will be used.
  129. /// </summary>
  130. public T Value
  131. {
  132. get
  133. {
  134. if (!this._wereValueDelegatesInvoked)
  135. {
  136. this._value = this.GetValue();
  137. }
  138. return this._value;
  139. }
  140. }
  141.  
  142. /// <summary>
  143. /// Return the value of the underlying object. If multiple delegates are specified, the first delegate to return a non-default value will be used.
  144. /// </summary>
  145. /// <returns>The value of the underlying object.</returns>
  146. protected T GetValue()
  147. {
  148. T value = default(T);
  149.  
  150. if (this.ValueDelegates != null)
  151. {
  152. foreach (Func<T> valueDelegate in this.ValueDelegates)
  153. {
  154. value = valueDelegate.Invoke();
  155. if (!Lazy<T>.IsNullOrDefault(value)) break;
  156. }
  157. }
  158.  
  159. this._wereValueDelegatesInvoked = true;
  160. return value;
  161. }
  162.  
  163. private static Boolean IsNullOrDefault(T value)
  164. {
  165. if (value == null) return true;
  166. else if (value.Equals(default(T))) return true;
  167. else return false;
  168. }
  169.  
  170. public override Boolean Equals(Object obj)
  171. {
  172. if (this.Value == null) return (obj == null);
  173. return this.Value.Equals(obj);
  174. }
  175.  
  176. public override Int32 GetHashCode()
  177. {
  178. if (this.Value == null) return base.GetHashCode();
  179. else return this.Value.GetHashCode();
  180. }
  181.  
  182. /// <summary>
  183. /// Returns the value of the <see cref="Lazy{T}" />.
  184. /// </summary>
  185. /// <param name="value">A <see cref="Lazy{T}" /> object.</param>
  186. /// <returns>The value of the <see cref="Value" /> property for the <paramref name="value" /> parameter.</returns>
  187. public static implicit operator T(Lazy<T> value)
  188. {
  189. return value.Value;
  190. }
  191.  
  192. /// <summary>
  193. /// Returns a <see cref="String" /> that represents the current <see cref="Lazy{T}" />.
  194. /// </summary>
  195. /// <returns>A <see cref="String" /> that represents the current <see cref="Lazy{T}" />.</returns>
  196. public override String ToString()
  197. {
  198. if (Lazy<T>.IsNullOrDefault(this.Value)) return null;
  199. else return this.Value.ToString();
  200. }
  201. }
  202.  
  203. [TestMethod]
  204. public void ABadFakeWorkExample()
  205. {
  206. var myLazyObject = new Lazy<Object>((() => { Thread.Sleep(5000); return new Object(); }));
  207.  
  208. Assert.IsNotNull(myLazyObject);
  209. }
  210.  
  211. [TestMethod]
  212. public void LazyUsesFirstNonDefaultResult()
  213. {
  214. Lazy<DateTime> lazy = new Lazy<DateTime>(
  215. (() => { return default(DateTime); }),
  216. (() => { return DateTime.Now; }),
  217. (() => { return default(DateTime); }));
  218.  
  219. Assert.AreNotEqual(default(DateTime), lazy.Value, "D'OH!");
  220. }
  221.  
  222. private LazyInit<Foo> fooHolder;
Add Comment
Please, Sign In to add comment