PageRenderTime 31ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Collections/CovariantExtensions.cs

#
C# | 370 lines | 204 code | 30 blank | 136 comment | 1 complexity | 0325cfe1dcdd099af14f3c8752160dd2 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using NUnit.Framework;
  5. namespace Delta.Utilities.Collections
  6. {
  7. /// <summary>
  8. /// Provides extensions to implement covariance of generic types, make sure
  9. /// to use this namespace when using this extensions.
  10. /// </summary>
  11. public static class CovariantExtensions
  12. {
  13. #region CollectionInterfaceAdapter Class
  14. /// <summary>
  15. /// Allows for covariance of generic ICollections. Adapts a collection of
  16. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  17. /// Credits go to the Umbrella (http://codeplex.com/umbrella) project
  18. /// </summary>
  19. /// <typeparam name="T">T</typeparam>
  20. /// <typeparam name="U">U</typeparam>
  21. private class CollectionInterfaceAdapter<T, U>
  22. : EnumerableInterfaceAdapter<T, U>, ICollection<U>
  23. where T : U
  24. {
  25. #region Count (Public)
  26. /// <summary>
  27. /// Count
  28. /// </summary>
  29. /// <typeparam name="T">T</typeparam>
  30. /// <typeparam name="U">U</typeparam>
  31. public int Count
  32. {
  33. get
  34. {
  35. return Target.Count;
  36. }
  37. }
  38. #endregion
  39. #region IsReadOnly (Public)
  40. /// <summary>
  41. /// Is read only
  42. /// </summary>
  43. /// <typeparam name="T">T</typeparam>
  44. /// <typeparam name="U">U</typeparam>
  45. public bool IsReadOnly
  46. {
  47. get
  48. {
  49. return Target.IsReadOnly;
  50. }
  51. }
  52. #endregion
  53. #region Private
  54. #region Target (Private)
  55. /// <summary>
  56. /// Target
  57. /// </summary>
  58. /// <typeparam name="T">T</typeparam>
  59. /// <typeparam name="U">U</typeparam>
  60. private new ICollection<T> Target
  61. {
  62. get;
  63. set;
  64. }
  65. #endregion
  66. #endregion
  67. #region Constructors
  68. /// <summary>
  69. /// Collection interface adapter
  70. /// </summary>
  71. /// <param name="target">Target collection to create from</param>
  72. public CollectionInterfaceAdapter(ICollection<T> target)
  73. : base(target)
  74. {
  75. }
  76. #endregion
  77. #region ICollection<U> Members
  78. /// <summary>
  79. /// Add
  80. /// </summary>
  81. /// <param name="item">Item</param>
  82. public void Add(U item)
  83. {
  84. Target.Add((T)item);
  85. }
  86. /// <summary>
  87. /// Clear
  88. /// </summary>
  89. public void Clear()
  90. {
  91. Target.Clear();
  92. }
  93. /// <summary>
  94. /// Contains
  95. /// </summary>
  96. /// <param name="item">Item</param>
  97. /// <returns>True if the item was found, false otherwise</returns>
  98. public bool Contains(U item)
  99. {
  100. return Target.Contains((T)item);
  101. }
  102. /// <summary>
  103. /// Copy to array.
  104. /// </summary>
  105. /// <param name="array">Array to copy into</param>
  106. /// <param name="arrayIndex">Array index to start copying into</param>
  107. public void CopyTo(U[] array, int arrayIndex)
  108. {
  109. int index = 0;
  110. foreach (U element in Target)
  111. {
  112. if (index >= arrayIndex)
  113. {
  114. array[index] = element;
  115. }
  116. index++;
  117. }
  118. }
  119. /// <summary>
  120. /// Remove item from the target collection.
  121. /// </summary>
  122. /// <param name="item">Item</param>
  123. /// <returns>
  124. /// True if removing the item succeeded, false otherwise.
  125. /// </returns>
  126. public bool Remove(U item)
  127. {
  128. return Target.Remove((T)item);
  129. }
  130. #endregion
  131. }
  132. #endregion
  133. #region EnumerableInterfaceAdapter Class
  134. /// <summary>
  135. /// Allows for covariance of generic IEnumerables. Adapts a collection of type
  136. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  137. /// </summary>
  138. /// <typeparam name="T">T</typeparam>
  139. /// <typeparam name="U">U</typeparam>
  140. private class EnumerableInterfaceAdapter<T, U> : IEnumerable<U>
  141. where T : U
  142. {
  143. #region Target (Public)
  144. /// <summary>
  145. /// Target
  146. /// </summary>
  147. /// <typeparam name="T">T</typeparam>
  148. /// <typeparam name="U">U</typeparam>
  149. public IEnumerable<T> Target
  150. {
  151. get;
  152. set;
  153. }
  154. #endregion
  155. #region Constructors
  156. /// <summary>
  157. /// Enumerable interface adapter
  158. /// </summary>
  159. /// <param name="target">Target</param>
  160. public EnumerableInterfaceAdapter(IEnumerable<T> target)
  161. {
  162. Target = target;
  163. }
  164. #endregion
  165. #region IEnumerable Members
  166. IEnumerator IEnumerable.GetEnumerator()
  167. {
  168. return GetEnumerator();
  169. }
  170. #endregion
  171. #region IEnumerable<U> Members
  172. /// <summary>
  173. /// Get enumerator
  174. /// </summary>
  175. /// <returns>Enumerator item for the target collection.</returns>
  176. public IEnumerator<U> GetEnumerator()
  177. {
  178. foreach (T item in Target)
  179. {
  180. yield return item;
  181. }
  182. }
  183. #endregion
  184. }
  185. #endregion
  186. #region ListInterfaceAdapter Class
  187. /// <summary>
  188. /// Allows for covariance of generic ILists. Adapts a collection of type
  189. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  190. /// </summary>
  191. /// <typeparam name="T">T</typeparam>
  192. /// <typeparam name="U">U</typeparam>
  193. private class ListInterfaceAdapter<T, U>
  194. : CollectionInterfaceAdapter<T, U>,
  195. IList<U>
  196. where T : U
  197. {
  198. #region Item (Public)
  199. /// <summary>
  200. /// Get Item via indexer.
  201. /// </summary>
  202. /// <param name="index">Index</param>
  203. /// <returns>Item</returns>
  204. public U this[int index]
  205. {
  206. get
  207. {
  208. return Target[index];
  209. }
  210. set
  211. {
  212. Target[index] = (T)value;
  213. }
  214. }
  215. #endregion
  216. #region Private
  217. #region Target (Private)
  218. /// <summary>
  219. /// Target
  220. /// </summary>
  221. /// <typeparam name="T">T</typeparam>
  222. /// <typeparam name="U">U</typeparam>
  223. private new IList<T> Target
  224. {
  225. get;
  226. set;
  227. }
  228. #endregion
  229. #endregion
  230. #region Constructors
  231. /// <summary>
  232. /// List interface adapter
  233. /// </summary>
  234. /// <param name="target">Target list to work on</param>
  235. public ListInterfaceAdapter(IList<T> target)
  236. : base(target)
  237. {
  238. }
  239. #endregion
  240. #region IList<U> Members
  241. /// <summary>
  242. /// Index of item
  243. /// </summary>
  244. /// <param name="item">Item</param>
  245. /// <returns>Index of the item if found</returns>
  246. public int IndexOf(U item)
  247. {
  248. return Target.IndexOf((T)item);
  249. }
  250. /// <summary>
  251. /// Insert
  252. /// </summary>
  253. /// <param name="index">Index</param>
  254. /// <param name="item">Item</param>
  255. public void Insert(int index, U item)
  256. {
  257. Target.Insert(index, (T)item);
  258. }
  259. /// <summary>
  260. /// Remove at
  261. /// </summary>
  262. /// <param name="index">Index</param>
  263. public void RemoveAt(int index)
  264. {
  265. Target.RemoveAt(index);
  266. }
  267. #endregion
  268. }
  269. #endregion
  270. #region ToCovariant (Static)
  271. /// <summary>
  272. /// Allows for covariance of generic ICollections. Adapts a collection of
  273. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  274. /// </summary>
  275. /// <typeparam name="T">T</typeparam>
  276. /// <typeparam name="U">U</typeparam>
  277. /// <returns>Covariant collection created from the source.</returns>
  278. public static ICollection<U> ToCovariant<T, U>(this ICollection<T> source)
  279. where T : U
  280. {
  281. return new CollectionInterfaceAdapter<T, U>(source);
  282. }
  283. /// <summary>
  284. /// Allows for covariance of generic ILists. Adapts a collection of type
  285. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  286. /// </summary>
  287. /// <typeparam name="T">T</typeparam>
  288. /// <typeparam name="U">U</typeparam>
  289. /// <param name="source">Source</param>
  290. /// <returns>Covariant list from the source list.</returns>
  291. public static IList<U> ToCovariant<T, U>(this IList<T> source)
  292. where T : U
  293. {
  294. return new ListInterfaceAdapter<T, U>(source);
  295. }
  296. /// <summary>
  297. /// Allows for covariance of generic IEnumerables. Adapts a collection of
  298. /// <typeparam name="T" /> into a collection of type <typeparam name="U" />
  299. /// </summary>
  300. /// <typeparam name="T">T</typeparam>
  301. /// <typeparam name="U">U</typeparam>
  302. /// <param name="source">Source</param>
  303. /// <returns>Covariant enumerable from the source enumerable.</returns>
  304. public static IEnumerable<U> ToCovariant<T, U>(this IEnumerable<T> source)
  305. where T : U
  306. {
  307. return new EnumerableInterfaceAdapter<T, U>(source);
  308. }
  309. #endregion
  310. /// <summary>
  311. /// CovariantExtensions Tests
  312. /// </summary>
  313. internal class CovariantExtensionsTests
  314. {
  315. #region Helpers
  316. private interface IFoo
  317. {
  318. }
  319. #endregion
  320. #region Helpers
  321. private interface IBar : IFoo
  322. {
  323. }
  324. #endregion
  325. #region ShouldConvertCollections
  326. /// <summary>
  327. /// Should convert collections
  328. /// </summary>
  329. [Test]
  330. public void ShouldConvertCollections()
  331. {
  332. var barcol = new Collection<IBar>();
  333. IList<IFoo> foocol = barcol.ToCovariant<IBar, IFoo>();
  334. ICollection<IFoo> foo2 = barcol.ToCovariant<IBar, IFoo>();
  335. IEnumerable<IFoo> foo3 = barcol.ToCovariant<IBar, IFoo>();
  336. }
  337. #endregion
  338. }
  339. }
  340. }