PageRenderTime 247ms CodeModel.GetById 101ms app.highlight 100ms RepoModel.GetById 31ms app.codeStats 1ms

/Utilities/Helpers/ArrayHelper.cs

#
C# | 1690 lines | 1028 code | 116 blank | 546 comment | 152 complexity | 16ca740437cf6fdf9e0a239565ae6d1b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1using System;
   2using System.Collections;
   3using System.Collections.Generic;
   4using System.IO;
   5using System.Text;
   6using NUnit.Framework;
   7
   8namespace Delta.Utilities.Helpers
   9{
  10	/// <summary>
  11	/// Array helper class adding extra functionality to the System.Array class
  12	/// and similar classes (lists). Most useful methods here are resizing
  13	/// arrays, building sub arrays and adding arrays together.
  14	/// </summary>
  15	public static class ArrayHelper
  16	{
  17		#region Delegates
  18		/// <summary>
  19		/// Parameterless delegate for code that should be invoked by the
  20		/// FreeDataWhenMemoryIsLow event handler.
  21		/// </summary>
  22		public delegate void FreeMemoryDelegate();
  23		#endregion
  24
  25		#region GetSubArray (Static)
  26		/// <summary>
  27		/// Get sub array (similar to String.Substring), again there is no function
  28		/// for arrays to do that easily.
  29		/// </summary>
  30		/// <typeparam name="T">Type of array</typeparam>
  31		/// <param name="length">
  32		/// Length of data to copy (can be smaller than originalData array size)
  33		/// </param>
  34		/// <param name="originalData">Data to grab from (full array)</param>
  35		/// <param name="startIndex">Start index for originalData</param>
  36		/// <returns>New array of type T with the specified length</returns>
  37		/// <exception cref="ArgumentOutOfRangeException">
  38		/// <c>startIndex</c> is out of range.
  39		/// </exception>
  40		public static T[] GetSubArray<T>(
  41			this T[] originalData, int startIndex, int length)
  42		{
  43			if (startIndex > originalData.Length)
  44			{
  45				throw new ArgumentOutOfRangeException("startIndex",
  46					"Must be smaller than originalData.Length=" + originalData.Length);
  47			}
  48			if (length > startIndex + originalData.Length)
  49			{
  50				throw new ArgumentOutOfRangeException("length",
  51					"Must be smaller than startIndex=" + startIndex +
  52					"+originalData.Length=" + originalData.Length);
  53			}
  54
  55			T[] ret = new T[length];
  56			Array.Copy(originalData, startIndex, ret, 0, length);
  57			return ret;
  58		}
  59
  60		/// <summary>
  61		/// Get sub array (similar to String.Substring), again there is no function
  62		/// for arrays to do that easily.
  63		/// </summary>
  64		/// <typeparam name="T">Type of array</typeparam>
  65		/// <param name="originalData">Original Data</param>
  66		/// <param name="startIndex">Start Index</param>
  67		public static T[] GetSubArray<T>(this T[] originalData, int startIndex)
  68		{
  69			return GetSubArray(originalData, startIndex,
  70				originalData.Length - startIndex);
  71		}
  72		#endregion
  73
  74		#region Resize (Static)
  75		/// <summary>
  76		/// Resize array, will create a new array with specified size, then copy
  77		/// all data (with Array.Copy, which is fast) and return the new array.
  78		/// There is no other faster possibility for managed arrays in C#!
  79		/// </summary>
  80		/// <param name="sourceArray">Source array to grab data from, can be
  81		/// bigger or smaller.</param>
  82		/// <param name="newLength">New length for the array we return here</param>
  83		/// <returns>The reduced or increased array</returns>
  84		public static Array Resize(this Array sourceArray, int newLength)
  85		{
  86			// Construct array of same type
  87			Array newArray = Array.CreateInstance(
  88				sourceArray.GetType().GetElementType(),
  89				newLength);
  90			// Copy data
  91			Array.Copy(sourceArray, 0, newArray, 0,
  92				// Don't copy more than any of these 2 arrays can handle!
  93				Math.Min(sourceArray.Length, newArray.Length));
  94			// Return resized array
  95			return newArray;
  96		}
  97
  98		/// <summary>
  99		/// If you need to resize a generic list into another generic list,
 100		/// use Resize. But Resize is slow, the generation of the new list
 101		/// takes some time, use this function to speed that up to 50% faster.
 102		/// It will return a simple array, if this is whats you need you
 103		/// have almost as good as the performance of the normal Resize method.
 104		/// </summary>
 105		/// <typeparam name="T">Type for the sourceArray list</typeparam>
 106		/// <param name="sourceArray">Input</param>
 107		/// <param name="newLength">New desired length for resized array</param>
 108		/// <returns>Resized array, if you need a list, use ResizeSlow</returns>
 109		public static T[] Resize<T>(this List<T> sourceArray, int newLength)
 110		{
 111			// Construct array of same type
 112			T[] newArray = new T[newLength];
 113			// Copy data
 114			sourceArray.CopyTo(0, newArray, 0,
 115				// Don't copy more than any of these 2 arrays can handle!
 116				Math.Min(sourceArray.Count, newArray.Length));
 117			// Return resized array
 118			return newArray;
 119		}
 120		#endregion
 121
 122		#region IsEqualWithoutOrder (Static)
 123		/// <summary>
 124		/// Returns 'true' if both list matches, this means, they have the same
 125		/// elements but the order of the elements doesn't matter.
 126		/// </summary>
 127		/// <typeparam name="T">Type of arrays to compare</typeparam>
 128		/// <param name="list1">List 1</param>
 129		/// <param name="list2">List 2</param>
 130		/// <returns>Returns 'true' if both list matches</returns>
 131		public static bool IsEqualWithoutOrder<T>(this T[] list1, T[] list2)
 132		{
 133			#region Validation check
 134			if (list1 == null || list2 == null ||
 135			    list1.Length != list2.Length)
 136			{
 137				return false;
 138			}
 139			#endregion
 140
 141			// Just iterate over all list values
 142			for (int i = 0; i < list1.Length; i++)
 143			{
 144				// and look
 145				bool isNotFound = true;
 146				for (int j = 0; j < list2.Length; j++)
 147				{
 148					// if the current value of the first list exists somewhere at any
 149					// position in the other list
 150					if (list1[i].Equals(list2[j]))
 151					{
 152						// Ok found ^^
 153						isNotFound = false;
 154						break;
 155					}
 156				}
 157
 158				// else if the current value doesn't exist in the other list, then they
 159				// don't match (even by ignoring the ordering)
 160				if (isNotFound)
 161				{
 162					return false;
 163				}
 164			}
 165
 166			// We haven't jumped out yet, so both lists are equal :)
 167			return true;
 168		}
 169		#endregion
 170
 171		#region Compare (Static)
 172		/// <summary>
 173		/// Compare 2 generic Lists. Returns 'true' if both list matches, this
 174		/// means, they have the same elements in the same order.
 175		/// </summary>
 176		/// <typeparam name="T">Type of lists to compare</typeparam>
 177		/// <param name="list1">List 1</param>
 178		/// <param name="list2">List 2</param>
 179		/// <returns>Returns 'true' if both list matches</returns>
 180		public static bool Compare<T>(IList<T> list1, IList<T> list2)
 181			where T : IEquatable<T>
 182		{
 183			// If both lists are exactly equal, we can skip checking
 184			if (list1 == list2)
 185			{
 186				return true;
 187			}
 188
 189			// Validation check
 190			if (list1 == null ||
 191			    list2 == null ||
 192			    list1.Count != list2.Count)
 193			{
 194				return false;
 195			}
 196
 197			// Go through the whole list and abort if anything is different
 198			for (int num = 0; num < list1.Count; num++)
 199			{
 200				if (list1[num].Equals(list2[num]) == false)
 201				{
 202					return false;
 203				}
 204			}
 205
 206			// Everything was checked, both lists have the same values
 207			return true;
 208		}
 209
 210		/// <summary>
 211		/// Compare 2 arrays, optimized for bytes, which are compared quite often.
 212		/// Returns 'true' if both list matches, this means, they have the same
 213		/// elements in the same order.
 214		/// </summary>
 215		/// <param name="list1">First bytes array</param>
 216		/// <param name="list2">Second bytes array</param>
 217		/// <returns>Returns 'true' if both list matches</returns>
 218		public static bool Compare(byte[] list1, byte[] list2)
 219		{
 220			// If both lists are exactly equal, we can skip checking
 221			if (list1 == list2)
 222			{
 223				return true;
 224			}
 225
 226			// Validation check
 227			if (list1 == null ||
 228			    list2 == null ||
 229			    list1.Length != list2.Length)
 230			{
 231				return false;
 232			}
 233
 234			// Go through the whole list and abort if anything is different
 235			for (int num = 0; num < list1.Length; num++)
 236			{
 237				if (list1[num] != list2[num])
 238				{
 239					return false;
 240				}
 241			}
 242
 243			// Everything was checked, both lists have the same values
 244			return true;
 245		}
 246		#endregion
 247
 248		#region Add (Static)
 249		/// <summary>
 250		/// Adds 2 arrays, pretty simple, but not implemented in Array!
 251		/// </summary>
 252		/// <param name="array1">Array 1</param>
 253		/// <param name="array2">Array 2</param>
 254		/// <returns>Big new array containing array1 and array2</returns>
 255		public static Array Add(this Array array1, Array array2)
 256		{
 257			// Construct array of same type
 258			Array newArray = Array.CreateInstance(
 259				array1.GetType().GetElementType(),
 260				array1.Length + array2.Length);
 261			// Copy data
 262			Array.Copy(array1, 0, newArray, 0, array1.Length);
 263			Array.Copy(array2, 0, newArray, array1.Length, array2.Length);
 264			// Return new array
 265			return newArray;
 266		}
 267
 268		/// <summary>
 269		/// Adds 2 arrays, pretty simple, but not implemented in Array!
 270		/// </summary>
 271		/// <param name="array1">Array 1</param>
 272		/// <param name="array2">Array 2</param>
 273		/// <returns>Big new array containing array1 and array2</returns>
 274		public static byte[] Add(this byte[] array1, byte[] array2)
 275		{
 276			// Construct array of same type
 277			byte[] newArray = new byte[array1.Length + array2.Length];
 278			// Copy data
 279			Array.Copy(array1, 0, newArray, 0, array1.Length);
 280			Array.Copy(array2, 0, newArray, array1.Length, array2.Length);
 281			// Return new array
 282			return newArray;
 283		}
 284
 285		/// <summary>
 286		/// For generic lists we can simply use .AddRange to do this!
 287		/// Use this method only if you want to create a new list from the
 288		/// first list + all data in the second list.
 289		/// </summary>
 290		/// <typeparam name="T">Type of lists</typeparam>
 291		/// <param name="list1">List 1</param>
 292		/// <param name="list2">List 2</param>
 293		/// <returns>Big new array containing array1 and array2</returns>
 294		public static List<T> Add<T>(this List<T> list1, List<T> list2)
 295		{
 296			List<T> retList = new List<T>(list1);
 297			retList.AddRange(list2);
 298			return retList;
 299		}
 300		#endregion
 301
 302		#region ConvertStringToIntArray (Static)
 303		/// <summary>
 304		/// Convert string data to int array, string must be in the form
 305		/// "1, 3, 8, 7", etc. WriteArrayData is the complementary function.
 306		/// </summary>
 307		/// <param name="text">Input text to be split up, if empty this method
 308		/// will return an empty array.</param>
 309		/// <returns>int array, will be null if string is invalid!</returns>
 310		public static int[] ConvertStringToIntArray(string text)
 311		{
 312			// Invalid?
 313			if (text == null ||
 314			    text.Length == 0)
 315			{
 316				return null;
 317			}
 318
 319			string[] splitted = text.Split(new[]
 320			{
 321				',', ' '
 322			},
 323				StringSplitOptions.RemoveEmptyEntries);
 324			List<int> ret = new List<int>(); //new int[splitted.Length];
 325			for (int i = 0; i < splitted.Length; i++)
 326			{
 327				int newValue;
 328				if (int.TryParse(splitted[i], out newValue))
 329				{
 330					ret.Add(newValue);
 331				}
 332			}
 333
 334			return ret.ToArray();
 335		}
 336		#endregion
 337
 338		#region ConvertByteArrayToIntArray (Static)
 339		/// <summary>
 340		/// Convert byte array to int array, we use 4 bytes and combine them
 341		/// into 1 int (first byte gets shifted 24 bits, next 16, next 8, next 0)
 342		/// </summary>
 343		/// <param name="byteArray">Byte Array</param>
 344		/// <returns>Integer array, has byteArray.Length/4 Length!</returns>
 345		public static int[] ConvertByteArrayToIntArray(byte[] byteArray)
 346		{
 347			// Invalid or too small?
 348			if (byteArray == null ||
 349			    byteArray.Length < 4)
 350			{
 351				return null;
 352			}
 353
 354			// 8bit per element to 32bit = /4
 355			int[] ret = new int[byteArray.Length / 4];
 356			for (int i = 0; i < ret.Length; i++)
 357			{
 358				ret[i] =
 359					(byteArray[i * 4 + 0]) +
 360					(byteArray[i * 4 + 1] << 8) +
 361					(byteArray[i * 4 + 2] << 16) +
 362					(byteArray[i * 4 + 3] << 24);
 363			}
 364			return ret;
 365		}
 366		#endregion
 367
 368		#region ConvertIntArrayToByteArray (Static)
 369		/// <summary>
 370		/// Convert int array to byte array, we split each int into 4 bytes
 371		/// (first byte gets shifted 24 bits, next 16, next 8, next 0)
 372		/// </summary>
 373		/// <param name="intArray">Integer array</param>
 374		/// <returns>Byte array, has intArray.Length*4 Length!</returns>
 375		public static byte[] ConvertIntArrayToByteArray(int[] intArray)
 376		{
 377			// Invalid?
 378			if (intArray == null)
 379			{
 380				return null;
 381			}
 382
 383			// 32bit per element to 8bit = *4
 384			byte[] ret = new byte[intArray.Length * 4];
 385			for (int i = 0; i < ret.Length / 4; i++)
 386			{
 387				ret[i * 4 + 0] = (byte)(intArray[i]);
 388				ret[i * 4 + 1] = (byte)(intArray[i] >> 8);
 389				ret[i * 4 + 2] = (byte)(intArray[i] >> 16);
 390				ret[i * 4 + 3] = (byte)(intArray[i] >> 24);
 391			}
 392			return ret;
 393		}
 394		#endregion
 395
 396		#region ConvertByteArrayToString (Static)
 397		/// <summary>
 398		/// Convert a byte array to a string, converts each byte to a char
 399		/// and add them up to the returning string.
 400		/// Useful for generating string data from a byte stream (ANSI style).
 401		/// </summary>
 402		/// <param name="byteArray">Byte array to write from (interpreted as char
 403		/// values)</param>
 404		/// <returns>String with all char values from the byteArray</returns>
 405		public static string ConvertByteArrayToString(byte[] byteArray)
 406		{
 407			if (byteArray == null)
 408			{
 409				return "";
 410			}
 411
 412			StringBuilder ret = new StringBuilder(byteArray.Length);
 413			for (int num = 0; num < byteArray.Length; num++)
 414			{
 415				ret.Append((char)byteArray[num]);
 416			}
 417			return ret.ToString();
 418		}
 419		#endregion
 420
 421		#region ToText (Static)
 422		/// <summary>
 423		/// Converts the list of chars to a string.
 424		/// </summary>
 425		/// <param name="charList">Char list</param>
 426		public static string ToText(this IList<char> charList)
 427		{
 428			if (charList == null)
 429			{
 430				return "";
 431			} // if
 432
 433			// Note: We use here the StringBuilder because its appending of chars is
 434			// 20x faster than by a string
 435			StringBuilder buildString = new StringBuilder(charList.Count);
 436			for (int charId = 0; charId < charList.Count; charId++)
 437			{
 438				buildString.Append(charList[charId]);
 439			}
 440
 441			return buildString.ToString();
 442		}
 443		#endregion
 444
 445		#region RemoveIndex (Static)
 446		/// <summary>
 447		/// Remove a specific array element and return reduced array,
 448		/// often used in ArrayLists, but its more complicated for normal arrays!
 449		/// <para />
 450		/// Note: This method is slower than using dynamic lists.
 451		/// </summary>
 452		/// <typeparam name="T">Type of array data</typeparam>
 453		/// <param name="originalArray">Original Array</param>
 454		/// <param name="index">Index in originalArray</param>
 455		/// <returns>New array with the index removed</returns>
 456		public static T[] RemoveIndex<T>(T[] originalArray, int index)
 457		{
 458			if (index < 0 || originalArray == null ||
 459			    index >= originalArray.Length ||
 460			    originalArray.Length <= 1)
 461			{
 462				return originalArray;
 463			}
 464			T[] ret = new T[originalArray.Length - 1];
 465
 466			// First part until index
 467			for (int i = 0; i < index; i++)
 468			{
 469				ret[i] = originalArray[i];
 470			}
 471
 472			// Second part from index+1 to end
 473			for (int i = index; i < ret.Length; i++)
 474			{
 475				ret[i] = originalArray[i + 1];
 476			}
 477			return ret;
 478		}
 479		#endregion
 480
 481		#region SetBitInByteArray (Static)
 482		/// <summary>
 483		/// Set bit in byte array
 484		/// </summary>
 485		/// <param name="byteArray">Byte Array</param>
 486		/// <param name="pos">Position to set bit (in bit position)</param>
 487		/// <param name="val">Value to set, either true (1) or false (0)</param>
 488		/// <exception cref="IndexOutOfRangeException">
 489		/// Throws index out of range if the position is more than array.Length*8.
 490		/// </exception>
 491		public static void SetBitInByteArray(
 492			byte[] byteArray, int pos, bool val)
 493		{
 494			int bytePos = pos / 8;
 495			if (bytePos >= byteArray.Length)
 496			{
 497				throw new IndexOutOfRangeException(
 498					"SetBitInByteArray invalid pos=" + pos +
 499					" index, byteArray.Length=" + byteArray.Length);
 500			}
 501
 502			// Set bit at specified place or clear it
 503			if (val)
 504			{
 505				// Just bitwise or with specified bit
 506				byteArray[bytePos] |= (byte)(1 << (pos % 8));
 507			}
 508			else
 509			{
 510				// Create inverted bitmask (only bit position is set to 0)
 511				// then and this with given byte and we have cleared it!
 512				byteArray[bytePos] &= (byte)(~(1 << (pos % 8)));
 513			}
 514		}
 515		#endregion
 516
 517		#region GetBitInByteArray (Static)
 518		/// <summary>
 519		/// Get bit in byte array
 520		/// </summary>
 521		/// <param name="byteArray">Byte Array</param>
 522		/// <param name="pos">Position to set bit (in bit position)</param>
 523		/// <returns>Value to at bit position in byteArray, true (1) or false (0)
 524		/// </returns>
 525		/// <exception cref="IndexOutOfRangeException">
 526		/// Throws index out of range if the position is more than array.Length*8.
 527		/// </exception>
 528		public static bool GetBitInByteArray(
 529			byte[] byteArray, int pos)
 530		{
 531			int bytePos = pos / 8;
 532			if (bytePos >= byteArray.Length)
 533			{
 534				throw new IndexOutOfRangeException(
 535					"SetBitInByteArray invalid pos=" + pos +
 536					" index, byteArray.Length=" + byteArray.Length);
 537			}
 538
 539			// Check if bit is set, we simply shift byte as
 540			// much bit positions as we need and check if value is 1 there!
 541			return (byteArray[bytePos] & (1 << (pos % 8))) != 0;
 542		}
 543		#endregion
 544
 545		#region BuildCompressedByteArrayFromBoolArray (Static)
 546		/// <summary>
 547		/// Creates a byte array from bool array. E.g if bool array has 8 entries
 548		/// we can compress this into one single byte, if it has 21 entries we can
 549		/// use 3 bytes, etc.!
 550		/// </summary>
 551		/// <param name="boolArray">Bool array</param>
 552		/// <returns>Byte array containing all bits from the boolArray</returns>
 553		public static byte[] BuildCompressedByteArrayFromBoolArray(
 554			bool[] boolArray)
 555		{
 556			byte[] byteArray = new byte[1 + ((boolArray.Length - 1) / 8)];
 557			for (int i = 0; i < boolArray.Length; i++)
 558			{
 559				SetBitInByteArray(byteArray, i, boolArray[i]);
 560			}
 561			return byteArray;
 562		}
 563		#endregion
 564
 565		#region FillBoolArrayFromCompressedByteArray (Static)
 566		/// <summary>
 567		/// Rebuilds a bool array compressed with
 568		/// BuildCompressedByteArrayFromBoolArray. E.g. we can extract 8 bool
 569		/// entries from a byte or 14 entries from 2 bytes, etc.
 570		/// </summary>
 571		/// <param name="boolArray">Bool array</param>
 572		/// <param name="byteArray">Byte array, with is 8 times smaller than
 573		/// boolArray</param>
 574		public static void FillBoolArrayFromCompressedByteArray(
 575			bool[] boolArray, byte[] byteArray)
 576		{
 577			for (int i = 0; i < boolArray.Length; i++)
 578			{
 579				boolArray[i] = GetBitInByteArray(byteArray, i);
 580			}
 581		}
 582		#endregion
 583
 584		#region AreCollectionsEqual (Static)
 585		/// <summary>
 586		/// Determines if the two collections contain equal items in the same 
 587		/// order. The two collections do not need to be of the same type; it is
 588		/// permissible to compare an array and an OrderedBag, for instance.
 589		/// </summary>
 590		/// <remarks>The default sense of equality for T is used, as defined by T's
 591		/// implementation of IComparable&lt;T&gt;.Equals or object.Equals.
 592		/// </remarks>
 593		/// <typeparam name="T">The type of items in the collections.</typeparam>
 594		/// <param name="collection1">The first collection to compare.</param>
 595		/// <param name="collection2">The second collection to compare.</param>
 596		/// <returns>True if the collections have equal items in the same order.
 597		/// If both collections are empty, true is returned.</returns>
 598		public static bool AreCollectionsEqual<T>(IEnumerable<T> collection1,
 599			IEnumerable<T> collection2)
 600		{
 601			return AreCollectionsEqual(collection1, collection2,
 602				EqualityComparer<T>.Default);
 603		}
 604
 605		/// <summary>
 606		/// Determines if the two collections contain equal items in the same
 607		/// order. The passed instance of IEqualityComparer&lt;T&gt; is used for
 608		/// determining if two items are equal.
 609		/// </summary>
 610		/// <typeparam name="T">The type of items in the collections.</typeparam>
 611		/// <param name="collection1">The first collection to compare.</param>
 612		/// <param name="collection2">The second collection to compare.</param>
 613		/// <param name="equalityComparer">The IEqualityComparer&lt;T&gt; used to
 614		/// compare items for equality. 
 615		/// Only the Equals member function of this interface is called.</param>
 616		/// <returns>True if the collections have equal items in the same order.
 617		/// If both collections are empty, true is returned.</returns>
 618		/// <exception cref="ArgumentNullException"><paramref name="collection1"/>,
 619		/// <paramref name="collection2"/>, or <paramref name="equalityComparer"/>
 620		/// is null.</exception>
 621		public static bool AreCollectionsEqual<T>(IEnumerable<T> collection1,
 622			IEnumerable<T> collection2, IEqualityComparer<T> equalityComparer)
 623		{
 624			if (collection1 == null)
 625			{
 626				throw new ArgumentNullException("collection1");
 627			}
 628			if (collection2 == null)
 629			{
 630				throw new ArgumentNullException("collection2");
 631			}
 632			if (equalityComparer == null)
 633			{
 634				throw new ArgumentNullException("equalityComparer");
 635			}
 636
 637			using (IEnumerator<T> enum1 = collection1.GetEnumerator(),
 638			                      enum2 = collection2.GetEnumerator())
 639			{
 640				bool continue1, continue2;
 641
 642				// Go through all items until done
 643				for (;;)
 644				{
 645					continue1 = enum1.MoveNext();
 646					continue2 = enum2.MoveNext();
 647					if (!continue1 ||
 648					    !continue2)
 649					{
 650						break;
 651					}
 652
 653					if (!equalityComparer.Equals(enum1.Current, enum2.Current))
 654					{
 655						// The two items are not equal.
 656						return false;
 657					}
 658				}
 659
 660				// If both continue1 and continue2 are false, we reached the end of
 661				// both sequences at the same time and found success. If one is true
 662				// and one is false, the sequences were of difference lengths->failure.
 663				return (continue1 == continue2);
 664			}
 665		}
 666		#endregion
 667
 668		#region ToArray (Static)
 669		/// <summary>
 670		/// Create an array with the items in a collection.
 671		/// </summary>
 672		/// <remarks>
 673		/// If <paramref name="collection"/> implements ICollection&lt;T&gt;T, then
 674		/// ICollection&lt;T&gt;.CopyTo() is used to fill the array. Otherwise, the
 675		/// IEnumerable&lt;T&gt;.GetEnumerator() is used to fill the array.
 676		/// </remarks>
 677		/// <typeparam name="T">Element type of the collection.</typeparam>
 678		/// <param name="collection">Collection to create array from.</param>
 679		/// <returns>
 680		/// An array with the items from the collection, in enumeration order.
 681		/// </returns>
 682		/// <exception cref="ArgumentNullException">
 683		/// <paramref name="collection"/> is null.
 684		/// </exception>
 685		public static T[] ToArray<T>(IEnumerable<T> collection)
 686		{
 687			if (collection == null)
 688			{
 689				throw new ArgumentNullException("collection");
 690			}
 691
 692			ICollection<T> coll = collection as ICollection<T>;
 693			if (coll != null)
 694			{
 695				// Use ICollection methods to do it more efficiently.
 696				T[] array = new T[coll.Count];
 697				coll.CopyTo(array, 0);
 698				return array;
 699			}
 700			else
 701			{
 702				// We can't allocate the correct size array now, because IEnumerable 
 703				// doesn't have a Count property. We could enumerate twice, once to
 704				// count and once to copy. Or we could enumerate once, copying to a
 705				// List, then copy the list to the correct size array. The latter
 706				// algorithm seems more efficient, although it allocates extra memory
 707				// for the list which is then discarded.
 708				List<T> list = new List<T>(collection);
 709				return list.ToArray();
 710			}
 711		}
 712		#endregion
 713
 714		#region Write (Static)
 715		/// <summary>
 716		/// Returns a string with the array data separated with commas.
 717		/// This is the byte array version.
 718		/// </summary>
 719		/// <param name="array">Byte array</param>
 720		/// <returns>A string with the byte array data, comma separated</returns>
 721		public static string Write(this byte[] array)
 722		{
 723			string ret = "";
 724			if (array != null)
 725			{
 726				for (int i = 0; i < array.Length; i++)
 727				{
 728					ret +=
 729						(ret.Length == 0
 730						 	? ""
 731						 	: ", ") + array[i];
 732				}
 733			}
 734			return ret;
 735		}
 736
 737		/// <summary>
 738		/// Returns a string with the array data separated with commas.
 739		/// This is the int array version.
 740		/// </summary>
 741		/// <param name="array">Integer array</param>
 742		/// <returns>A string with the int array data, comma separated</returns>
 743		public static string Write(this int[] array)
 744		{
 745			string ret = "";
 746			if (array != null)
 747			{
 748				for (int i = 0; i < array.Length; i++)
 749				{
 750					ret +=
 751						(ret.Length == 0
 752						 	? ""
 753						 	: ", ") + array[i];
 754				}
 755			}
 756			return ret;
 757		}
 758
 759		/// <summary>
 760		/// Returns a string with the array data separated with commas.
 761		/// This is the general array version.
 762		/// </summary>
 763		/// <param name="array">Array of any type</param>
 764		/// <returns>A string with the array data, comma separated</returns>
 765		public static string Write(this Array array)
 766		{
 767			string ret = "";
 768			if (array != null)
 769			{
 770				for (int i = 0; i < array.Length; i++)
 771				{
 772					ret +=
 773						(ret.Length == 0
 774						 	? ""
 775						 	: ", ") +
 776						(array.GetValue(i) == null
 777						 	? "null"
 778						 	: StringHelper.ToInvariantString(array.GetValue(i)));
 779				}
 780			}
 781			return ret;
 782		}
 783
 784		/// <summary>
 785		/// Returns a string with the array data separated with commas.
 786		/// This is the general array version with maxLength bounding (will return
 787		/// string with max. this number of entries).
 788		/// </summary>
 789		/// <param name="list">List</param>
 790		/// <param name="maxLength">MaxLength</param>
 791		/// <returns>A string with the array data, comma separated</returns>
 792		public static string Write(this Array list, int maxLength)
 793		{
 794			string ret = "";
 795			if (list != null)
 796			{
 797				for (int i = 0; i < list.Length && i < maxLength; i++)
 798				{
 799					ret +=
 800						(ret.Length == 0
 801						 	? ""
 802						 	: ", ") +
 803						StringHelper.ToInvariantString(list.GetValue(i));
 804				}
 805			}
 806			return ret;
 807		}
 808
 809		/// <summary>
 810		/// Returns a string with the array data separated with commas.
 811		/// </summary>
 812		/// <param name="list">List</param>
 813		/// <returns>A string with the array data, comma separated</returns>
 814		public static string Write(this ICollection list)
 815		{
 816			return Write(list, ", ");
 817		}
 818
 819		/// <summary>
 820		/// Returns a string with the array data with given separator.
 821		/// </summary>
 822		/// <param name="list">List to write out</param>
 823		/// <param name="separator">Separator</param>
 824		/// <returns>A string with the array data, comma separated</returns>
 825		public static string Write(this ICollection list, string separator)
 826		{
 827			string ret = "";
 828			if (list != null)
 829			{
 830				foreach (object obj in list)
 831				{
 832					ret +=
 833						(ret.Length == 0
 834						 	? ""
 835						 	: separator) +
 836						StringHelper.ToInvariantString(obj);
 837				}
 838			}
 839			return ret;
 840		}
 841
 842		/// <summary>
 843		/// Returns a string with the array data separated with commas.
 844		/// This is the List&lt;T&gt; version.
 845		/// </summary>
 846		/// <typeparam name="T">Type of list data</typeparam>
 847		/// <param name="list">List to write out</param>
 848		/// <returns>A string with the list data, comma separated</returns>
 849		public static string Write<T>(this List<T> list)
 850		{
 851			string ret = "";
 852			if (list != null)
 853			{
 854				foreach (T obj in list)
 855				{
 856					ret +=
 857						(ret.Length == 0
 858						 	? ""
 859						 	: ", ") +
 860						StringHelper.ToInvariantString(obj);
 861				}
 862			}
 863			return ret;
 864		}
 865
 866		/// <summary>
 867		/// Returns a string with the array data separated with commas.
 868		/// This is the List&lt;T&gt; version with a maximum count.
 869		/// </summary>
 870		/// <typeparam name="T">Type of list data</typeparam>
 871		/// <param name="count">Count</param>
 872		/// <param name="list">List</param>
 873		/// <returns>A string with the list data, comma separated</returns>
 874		public static string Write<T>(this List<T> list, int count)
 875		{
 876			string ret = "";
 877			if (list != null)
 878			{
 879				for (int i = 0; i < list.Count && i < count; i++)
 880				{
 881					ret +=
 882						(ret.Length == 0
 883						 	? ""
 884						 	: ", ") +
 885						StringHelper.ToInvariantString(list[i]);
 886				}
 887			}
 888			return ret;
 889		}
 890
 891		/// <summary>
 892		/// Returns a string with the array data with given separator.
 893		/// This is the List&lt;T&gt; version.
 894		/// </summary>
 895		/// <typeparam name="T">Type of the list data, often strings</typeparam>
 896		/// <param name="list">List to concatenate</param>
 897		/// <param name="separator">Separator used to separate (e.g. comma)</param>
 898		/// <returns>A string with the list data, separator separated</returns>
 899		public static string Write<T>(this List<T> list, string separator)
 900		{
 901			string ret = "";
 902			if (list != null)
 903			{
 904				foreach (T obj in list)
 905				{
 906					ret +=
 907						(ret.Length == 0
 908						 	? ""
 909						 	: separator) +
 910						StringHelper.ToInvariantString(obj);
 911				}
 912			}
 913			return ret;
 914		}
 915
 916		/// <summary>
 917		/// Returns a string with the array data separated with commas.
 918		/// This is the enumerable class version.
 919		/// </summary>
 920		/// <param name="enumerableClass">Enumerable class</param>
 921		/// <returns>A string with the list data, comma separated</returns>
 922		public static string Write(this IEnumerable enumerableClass)
 923		{
 924			return Write(enumerableClass, ", ");
 925		}
 926
 927		/// <summary>
 928		/// Returns a string with the array data separated with commas.
 929		/// This is the enumerable class version.
 930		/// </summary>
 931		/// <param name="enumerableClass">Enumerable class</param>
 932		/// <param name="separator">Separator</param>
 933		/// <returns>A string with the list data, comma separated</returns>
 934		public static string Write(this IEnumerable enumerableClass,
 935			string separator)
 936		{
 937			string ret = "";
 938			if (enumerableClass != null)
 939			{
 940				foreach (object obj in enumerableClass)
 941				{
 942					ret +=
 943						(ret.Length == 0
 944						 	? ""
 945						 	: separator) +
 946						StringHelper.ToInvariantString(obj);
 947				}
 948			}
 949			return ret;
 950		}
 951		#endregion
 952
 953		#region WriteFirstAndLastValues (Static)
 954		/// <summary>
 955		/// Write array data first and last values, e.g. the first 10 and the
 956		/// last 10 values of a really long array (e.g. a network package).
 957		/// All values are separated by commas.
 958		/// <para />
 959		/// Note: If the array has less entries than numberOfItemsAtStartAndEnd
 960		/// times two, we will just display the whole array.
 961		/// </summary>
 962		/// <param name="list">List to grab data from, can be huge</param>
 963		/// <param name="numberOfItemsAtStartAndEnd">Number of items at start and
 964		/// end we want to have in the output string</param>
 965		/// <returns>A string with the list data, comma separated</returns>
 966		public static string WriteFirstAndLastValues(this Array list,
 967			int numberOfItemsAtStartAndEnd)
 968		{
 969			string ret = "";
 970			if (list != null)
 971			{
 972				// If the array has less entries than numberOfItemsAtStartAndEnd * 2,
 973				// display the whole array normally.
 974				if (list.Length <= numberOfItemsAtStartAndEnd * 2)
 975				{
 976					return Write(list);
 977				}
 978
 979				for (int i = 0; i < list.Length && i < numberOfItemsAtStartAndEnd; i++)
 980				{
 981					ret += (ret.Length == 0
 982					        	? ""
 983					        	: ", ") +
 984					       StringHelper.ToInvariantString(list.GetValue(i));
 985				}
 986				ret += " ... ";
 987				for (int i = list.Length - numberOfItemsAtStartAndEnd;
 988					i >= 0 && i < list.Length;
 989					i++)
 990				{
 991					ret += (ret.EndsWith(" ... ")
 992					        	? ""
 993					        	: ", ") +
 994					       StringHelper.ToInvariantString(list.GetValue(i));
 995				}
 996			}
 997			return ret;
 998		}
 999		#endregion
1000
1001		#region ConcatenateCollections (Static)
1002		/// <summary>
1003		/// Concatenates all the items from several collections. The collections
1004		/// need not be of the same type, but must have the same item type.
1005		/// </summary>
1006		/// <param name="collections">Set of collections to concatenate.
1007		/// In many languages, this parameter can be specified as several
1008		/// individual parameters.</param>
1009		/// <returns>An IEnumerable that enumerates all the items in each of the
1010		/// collections, in order.</returns>
1011		public static IEnumerable<T> ConcatenateCollections<T>(
1012			IEnumerable<T>[] collections)
1013		{
1014			if (collections == null)
1015			{
1016				throw new ArgumentNullException("collections");
1017			}
1018
1019			foreach (IEnumerable<T> coll in collections)
1020			{
1021				foreach (T item in coll)
1022				{
1023					yield return item;
1024				}
1025			}
1026		}
1027		#endregion
1028
1029		#region Count (Static)
1030		/// <summary>
1031		/// Count the number of items in an IEnumerable&lt;T&gt; collection. If 
1032		/// a more specific collection type is being used, it is more efficient to
1033		/// use the Count property, if one is provided.
1034		/// </summary>
1035		/// <remarks>If the collection implements ICollection&lt;T&gt;, this method
1036		/// simply returns ICollection&lt;T&gt;.Count. Otherwise, it enumerates all
1037		/// items and counts them.</remarks>
1038		/// <param name="collection">The collection to count items in.</param>
1039		/// <returns>The number of items in the collection.</returns>
1040		/// <exception cref="ArgumentNullException"><paramref name="collection"/>
1041		/// is null.</exception>
1042		public static int Count<T>(IEnumerable<T> collection)
1043		{
1044			if (collection == null)
1045			{
1046				throw new ArgumentNullException("collection",
1047					"Unable to count number of items if no valid collection was given");
1048			}
1049
1050			// If it's really an ICollection, use that Count property as it is much
1051			// faster.
1052			ICollection<T> genericCollection = collection as ICollection<T>;
1053			if (genericCollection != null)
1054			{
1055				return genericCollection.Count;
1056			}
1057
1058			// Traverse the collection and count the elements.
1059			int count = 0;
1060			foreach (T item in collection)
1061			{
1062				// Dummy line to avoid Warning CA1804
1063				if (item.GetType() != null)
1064				{
1065					count++;
1066				}
1067			}
1068
1069			return count;
1070		}
1071		#endregion
1072
1073		#region CountEqual (Static)
1074		/// <summary>
1075		/// Counts the number of items in the collection that are equal to
1076		/// <paramref name="find"/>.
1077		/// </summary>
1078		/// <remarks>The default sense of equality for T is used, as defined by
1079		/// T's implementation of IComparable&lt;T&gt;.Equals or object.Equals.
1080		/// </remarks>
1081		/// <param name="collection">The collection to count items in.</param>
1082		/// <param name="find">The item to compare to.</param>
1083		/// <returns>The number of items in the collection that are equal to
1084		/// <paramref name="find"/>.</returns>
1085		public static int CountEqual<T>(IEnumerable<T> collection, T find)
1086		{
1087			return CountEqual(collection, find, EqualityComparer<T>.Default);
1088		}
1089
1090		/// <summary>
1091		/// Counts the number of items in the collection that are equal to
1092		/// <paramref name="find"/>.
1093		/// </summary>
1094		/// <param name="collection">The collection to count items in.</param>
1095		/// <param name="find">The item to compare to.</param>
1096		/// <param name="equalityComparer">The comparer to use to determine if
1097		/// two items are equal. Only the Equals member function will be called.
1098		/// </param>
1099		/// <returns>The number of items in the collection that are equal to
1100		/// <paramref name="find"/>.</returns>
1101		/// <exception cref="ArgumentException"><paramref name="collection"/> or
1102		/// <paramref name="equalityComparer"/> is null.</exception>
1103		public static int CountEqual<T>(IEnumerable<T> collection, T find,
1104			IEqualityComparer<T> equalityComparer)
1105		{
1106			if (collection == null)
1107			{
1108				throw new ArgumentException("collection");
1109			}
1110			if (equalityComparer == null)
1111			{
1112				throw new ArgumentNullException("equalityComparer");
1113			}
1114
1115			int count = 0;
1116			foreach (T item in collection)
1117			{
1118				if (equalityComparer.Equals(item, find))
1119				{
1120					++count;
1121				}
1122			}
1123
1124			return count;
1125		}
1126		#endregion
1127
1128		#region IsValidIndex (Static)
1129		/// <summary>
1130		/// Returns 'true' if the given index of the array stays in the
1131		/// "array range".
1132		/// </summary>
1133		/// <param name="arrayIndex">Array index</param>
1134		/// <param name="anyArray">Any array</param>
1135		/// <returns>'true' if the given index of the array stays in the range
1136		/// </returns>
1137		public static bool IsValidIndex(this IList list, int arrayIndex)
1138		{
1139			return list != null &&
1140						 arrayIndex < list.Count &&
1141			       arrayIndex > MathHelper.InvalidIndex;
1142		}
1143		#endregion
1144
1145		#region Pop (Static)
1146		/// <summary>
1147		/// Returns the top most item of the list and removes it from the list.
1148		/// Warning: This method is a bit slow because we need to change the list
1149		/// and removing the last entry is not as fast as for Collections like
1150		/// Queue, use it with care.
1151		/// </summary>
1152		/// <typeparam name="T">The object type in the list</typeparam>
1153		/// <param name="list">The list we want to pop from</param>
1154		/// <returns>The top most object of the list</returns>
1155		public static T Pop<T>(this List<T> list)
1156		{
1157			if (list.Count == 0)
1158			{
1159				throw new Exception("The list is empty!");
1160			}
1161
1162			T result = list[list.Count - 1];
1163			list.RemoveAt(list.Count - 1);
1164			return result;
1165		}
1166		#endregion
1167
1168		#region IsNullOrEmpty (Static)
1169		/// <summary>
1170		/// Helper method for a common check if an array is null or has no
1171		/// elements. Same as String.IsNullOrEmpty
1172		/// </summary>
1173		/// <param name="array">The array to check.</param>
1174		/// <returns>True if array is null or empty.</returns>
1175		public static bool IsNullOrEmpty(Array array)
1176		{
1177			return array == null ||
1178			       array.Length == 0;
1179		}
1180
1181		/// <summary>
1182		/// Helper method for a common check if a list is null or has no
1183		/// elements. Same as String.IsNullOrEmpty
1184		/// </summary>
1185		/// <param name="list">The list to check.</param>
1186		/// <returns>True if list is null or empty.</returns>
1187		public static bool IsNullOrEmpty<T>(List<T> list)
1188		{
1189			return list == null ||
1190			       list.Count == 0;
1191		}
1192		#endregion
1193
1194		#region SafeGet (Static)
1195		/// <summary>
1196		/// Gets given property value in a safe way (not found? then default is
1197		/// returned, otherwise the found object is returned).
1198		/// </summary>
1199		/// <param name="dict">Dictionary</param>
1200		/// <param name="key">Key</param>
1201		/// <returns>Value from dictionary or default value if not found</returns>
1202		public static ValueType SafeGet<KeyType, ValueType>(
1203			Dictionary<KeyType, object> dict, KeyType key)
1204		{
1205			if (dict.ContainsKey(key) == false)
1206			{
1207				return default(ValueType);
1208			}
1209
1210			ValueType result;
1211			try
1212			{
1213				result = (ValueType)dict[key];
1214			}
1215			catch
1216			{
1217				result = default(ValueType);
1218			}
1219			return result;
1220
1221			//return (ValueType)Convert.ChangeType(dict[key], typeof(ValueType));
1222		}
1223		#endregion
1224
1225		#region Save
1226		/// <summary>
1227		/// Helper method to save out an array of strings by just saving the length
1228		/// first and then all the data. Use LoadStrings to load the data again.
1229		/// </summary>
1230		/// <param name="someArray">Some string array with data</param>
1231		/// <param name="writer">Binary data writer</param>
1232		public static void Save(this string[] someArray, BinaryWriter writer)
1233		{
1234			if (writer == null)
1235			{
1236				Log.Warning("Unable to save array, writer is not valid!");
1237				return;
1238			}
1239			if (someArray == null)
1240			{
1241				writer.Write((int)0);
1242				return;
1243			}
1244
1245			writer.Write(someArray.Length);
1246			for (int num = 0; num < someArray.Length; num++)
1247			{
1248				writer.Write(someArray[num]);
1249			}
1250		}
1251
1252		/// <summary>
1253		/// Helper method to save out an array of integers by saving the length
1254		/// first and then all the data. Use LoadIntegers to load the data again.
1255		/// </summary>
1256		/// <param name="someArray">Some integer array with data</param>
1257		/// <param name="writer">Binary data writer</param>
1258		public static void Save(this int[] someArray, BinaryWriter writer)
1259		{
1260			if (writer == null)
1261			{
1262				Log.Warning("Unable to save array, writer is not valid!");
1263				return;
1264			}
1265			if (someArray == null)
1266			{
1267				writer.Write((int)0);
1268				return;
1269			}
1270
1271			writer.Write(someArray.Length);
1272			for (int num = 0; num < someArray.Length; num++)
1273			{
1274				writer.Write(someArray[num]);
1275			}
1276		}
1277		#endregion
1278
1279		#region Load
1280		/// <summary>
1281		/// Helper method to load an array of strings by first reading the length
1282		/// and then all the data. Use Save to save the data.
1283		/// </summary>
1284		/// <param name="reader">Binary data reader</param>
1285		/// <returns>String array with all the data filled in</returns>
1286		public static string[] LoadStrings(BinaryReader reader)
1287		{
1288			if (reader == null)
1289			{
1290				Log.Warning("Unable to read array, reader is not valid!");
1291				return new string[0];
1292			}
1293
1294			int length = reader.ReadInt32();
1295			string[] ret = new string[length];
1296			for (int num = 0; num < length; num++)
1297			{
1298				ret[num] = reader.ReadString();
1299			}
1300			return ret;
1301		}
1302
1303		/// <summary>
1304		/// Helper method to load an array of strings by first reading the length
1305		/// and then all the data. Use Save to save the data.
1306		/// </summary>
1307		/// <param name="reader">Binary data reader</param>
1308		/// <returns>String array with all the data filled in</returns>
1309		public static int[] LoadIntegers(BinaryReader reader)
1310		{
1311			if (reader == null)
1312			{
1313				Log.Warning("Unable to read array, reader is not valid!");
1314				return new int[0];
1315			}
1316
1317			int length = reader.ReadInt32();
1318			int[] ret = new int[length];
1319			for (int num = 0; num < length; num++)
1320			{
1321				ret[num] = reader.ReadInt32();
1322			}
1323			return ret;
1324		}
1325		#endregion
1326
1327		#region FreeDataWhenMemoryIsLow (Static)
1328		/// <summary>
1329		/// Event handler everyone can attach to for freeing unneeded memory.
1330		/// The primary user of this delegate are all Cache classes, which will
1331		/// allow to free cache data when memory is low. All data will be reloaded
1332		/// internally, so we just need some extra CPU time to recalculate
1333		/// everything, but we can save a lot of memory without having to go to
1334		/// real data that is currently needed, which is much harder to optimize.
1335		/// </summary>
1336		public static FreeMemoryDelegate FreeDataWhenMemoryIsLow;
1337		#endregion
1338		
1339		#region Internal
1340
1341		#region NumberOfCachesGenerated (Internal)
1342		/// <summary>
1343		/// Helper variable to keep track on how many caches were generated. Only
1344		/// used for warnings, debugging and profiling, but cannot be inside the
1345		/// generic Cache class because each input/output type combination would
1346		/// have its own counter, we want to know the overall number of caches.
1347		/// </summary>
1348		internal static int NumberOfCachesGenerated;
1349		#endregion
1350
1351		#endregion
1352
1353		/// <summary>
1354		/// ArrayHelper tests
1355		/// </summary>
1356		internal class ArrayHelperTests
1357		{
1358			#region CompareArrays (Static)
1359			/// <summary>
1360			/// Test compare arrays. Note: Too slow for a dynamic unit test.
1361			/// </summary>
1362			[Test]
1363			public static void CompareArrays()
1364			{
1365				// Compare 2 arrays
1366				int[] testArray1 = new int[4]
1367				{
1368					1, 4, 7, 5
1369				};
1370				int[] testArray2 = (int[])new int[2]
1371				{
1372					1, 4
1373				}.Add(new int[2]
1374				{
1375					7, 5
1376				});
1377				Assert.True(Compare(testArray1, testArray2));
1378
1379				// Compare 2 generic lists
1380				List<int> testList1 = new List<int>(new[]
1381				{
1382					4, 8
1383				});
1384				List<int> testList2 = new List<int>();
1385				testList2.Add(4);
1386				testList2.Add(8);
1387				Assert.True(Compare(testList1, testList2));
1388				Assert.True(testList1.Contains(8));
1389				Assert.False(testList1.Contains(2));
1390			}
1391			#endregion
1392
1393			#region IsNullOrEmpty (Static)
1394			/// <summary>
1395			/// Test the IsNullOrEmpty method.
1396			/// </summary>
1397			[Test]
1398			public static void IsNullOrEmpty()
1399			{
1400				string[] testArray = null;
1401				Assert.True(ArrayHelper.IsNullOrEmpty(testArray));
1402				testArray = new string[0];
1403				Assert.True(ArrayHelper.IsNullOrEmpty(testArray));
1404				testArray = new[]
1405				{
1406					"hello"
1407				};
1408				Assert.False(ArrayHelper.IsNullOrEmpty(testArray));
1409
1410				List<string> testList = null;
1411				Assert.True(ArrayHelper.IsNullOrEmpty(testList));
1412				testList = new List<string>();
1413				Assert.True(ArrayHelper.IsNullOrEmpty(testList));
1414				testList.Add("hello");
1415				Assert.False(ArrayHelper.IsNullOrEmpty(testList));
1416			}
1417			#endregion
1418
1419			#region SafeGet (Static)
1420			/// <summary>
1421			/// Test the SafeGet method.
1422			/// </summary>
1423			[Test]
1424			public static void SafeGet()
1425			{
1426				Dictionary<string, object> elements = new Dictionary<string, object>();
1427
1428				Assert.Null(SafeGet<string, Array>(elements, "key1"));
1429
1430				elements.Add("key2", 15);
1431				elements.Add("key3", 15.456f);
1432				elements.Add("key4", 15.1d);
1433
1434				Assert.Equal(SafeGet<string, int>(elements, "key2"),
1435					15);
1436				Assert.Equal(SafeGet<string, float>(elements, "key3"),
1437					15.456f);
1438				Assert.Equal(SafeGet<string, double>(elements, "key4"),
1439					15.1d);
1440				// Now we test an invalid cast which will return the default
1441				Assert.Equal(SafeGet<string, int>(elements, "key4"),
1442					0.0d);
1443			}
1444			#endregion
1445
1446			#region Resize
1447			/// <summary>
1448			/// Test resize
1449			/// </summary>
1450			[Test]
1451			public void Resize()
1452			{
1453				// Just resize a simple int array
1454				int[] testArray1 = {
1455					0, 1
1456				};
1457				Assert.Equal(6, testArray1.Resize(6).Length);
1458
1459				// Resize a generic list (returning an array, much faster)
1460				List<int> testArray3 = new List<int>(new[]
1461				{
1462					0, 1
1463				});
1464				Assert.Equal(6, testArray3.Resize(6).Length);
1465			}
1466			#endregion
1467
1468			#region IsEqual
1469			/// <summary>
1470			/// Is equal
1471			/// </summary>
1472			[Test]
1473			public void IsEqual()
1474			{
1475				int[] list = new[]
1476				{
1477					1, 2, 3
1478				};
1479				int[] unorderedList = new[]
1480				{
1481					2, 3, 1
1482				};
1483				int[] differentList = new[]
1484				{
1485					11, 2, 3
1486				};
1487
1488				Assert.True(list.IsEqualWithoutOrder(list));
1489				Assert.True(list.IsEqualWithoutOrder(unorderedList));
1490				Assert.False(list.IsEqualWithoutOrder(differentList));
1491			}
1492			#endregion
1493
1494			#region AddArrays
1495			/// <summary>
1496			/// Test add arrays
1497			/// </summary>
1498			[Test]
1499			public void AddArrays()
1500			{
1501				// Test adding normal arrays
1502				int[] testArray1 = {
1503					0, 1, 2, 3
1504				};
1505				int[] testArray2 = {
1506					4, 5, 3, 1
1507				};
1508				int[] testArray3 = (int[])testArray1.Add(testArray2);
1509				Assert.Equal(testArray3.Length,
1510					testArray1.Length + testArray2.Length);
1511				Assert.True(Compare(testArray3,
1512					new[]
1513					{
1514						0, 1, 2, 3, 4, 5, 3, 1
1515					}));
1516
1517				// Test adding generic lists
1518				List<int> testList1 = new List<int>(new[]
1519				{
1520					0, 1, 2
1521				});
1522				List<int> testList2 = new List<int>(new[]
1523				{
1524					6, 5, 4
1525				});
1526				List<int> testList3 = testList1.Add(testList2);
1527				Assert.Equal(testList3.Count,
1528					testList1.Count + testList2.Count);
1529				Assert.True(Compare(testList3,
1530					new[]
1531					{
1532						0, 1, 2, 6, 5, 4
1533					}));
1534			}
1535			#endregion
1536
1537			#region RemoveIndex
1538			/// <summary>
1539			/// Test remove index
1540			/// </summary>
1541			[Test]
1542			public void RemoveIndex()
1543			{
1544				int[] someArray = new[]
1545				{
1546					1, 2, 6, 3, 4
1547				};
1548				// Remove 6 and compare
1549				Assert.True(ArrayHelper.Compare(
1550					ArrayHelper.RemoveIndex(someArray, 2),
1551					new[]
1552					{
1553						1, 2, 3, 4
1554					}));
1555			}
1556			#endregion
1557
1558			#region GetSubArray
1559			/// <summary>
1560			/// Test get sub array
1561			/// </summary>
1562			[Test]
1563			public void GetSubArray()
1564			{
1565				// First test
1566				int[] someArray = new[]
1567				{
1568					1, 2, 3, 100, 200, 300, 4, 5, 6
1569				};
1570				Assert.True(Compare(
1571					someArray.GetSubArray(3, 3),
1572					new[]
1573					{
1574						100, 200, 300
1575					}));
1576
1577				// Another test
1578				float[] testNumbers = new float[]
1579				{
1580					0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
1581				};
1582				float[] extractedNumbers = testNumbers.GetSubArray(2, 4);
1583				Assert.Equal(new float[]
1584				{
1585					2, 3, 4, 5
1586				}, extractedNumbers);
1587			}
1588			#endregion
1589
1590			#region ConcatenateCollections
1591			/// <summary>
1592			/// Test concatenate collections
1593			/// </summary>
1594			[Test]
1595			public void ConcatenateCollections()
1596			{
1597				//int[] list1 = new int[] { 0, 1, 2, 3, 4 };
1598				//int[] list2 = new int[] { 5, 6, 7, 8, 9 };
1599				//int[] list3 = new int[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
1600				//int[] allLists = ArrayHelper.ToArray(ConcatenateCollections<int>(
1601				//  new int[][] { list1, list2, list3 }));
1602				//Assert.Equal(list1.Length + list2.Length + list3.Length,
1603				//  allLists.Length);
1604				//Assert.Equal("0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " +
1605				//  "10, 20, 30, 40, 50, 60, 70, 80, 90, 100",
1606				//  ArrayHelper.Write(allLists));
1607			}
1608			#endregion
1609
1610			#region AreCollectionsEqual
1611			/// <summary>
1612			/// Test are collections equal
1613			/// </summary>
1614			[Test]
1615			public void AreCollectionsEqual()
1616			{
1617				int[] list1 = new[]
1618				{
1619					1, 2, 3, 4, 5, 6
1620				};
1621				int[] list2 = new[]
1622				{
1623					1, 2, 3, 4, 5, 6, 7
1624				};
1625				int[] list3 = new[]
1626				{
1627					1, 2, 3, 4, 5, 6
1628				};
1629				Assert.False(ArrayHelper.AreCollectionsEqual(list1, list2));
1630				Assert.True(ArrayHelper.AreCollectionsEqual(list1, list3));
1631			}
1632			#endregion
1633
1634			#region ToArray
1635			/// <summary>
1636			/// Test to array
1637			/// </summary>
1638			[Test]
1639			public void ToArray()
1640			{
1641				List<string> someStrings = new List<string>();
1642				someStrings.Add("hi");
1643				someStrings.Add("there");
1644				someStrings.Add("whats");
1645				someStrings.Add("up");
1646				string[] stringArray = ArrayHelper.ToArray(someStrings);
1647				Assert.Equal("hi, there, whats, up",
1648					stringArray.Write());
1649				Assert.True(
1650					ArrayHelper.AreCollectionsEqual(someStrings, stringArray));
1651			}
1652			#endregion
1653
1654			#region IsValidIndex
1655			/// <summary>
1656			/// Is valid index
1657			/// </summary>
1658			[Test]
1659			public void IsValidIndex()
1660			{
1661				int[] testArray = new int[

Large files files are truncated, but you can click here to view the full file