PageRenderTime 140ms CodeModel.GetById 56ms app.highlight 11ms RepoModel.GetById 69ms app.codeStats 1ms

/Utilities/Collections/CovariantExtensions.cs

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