PageRenderTime 1189ms CodeModel.GetById 212ms app.highlight 224ms RepoModel.GetById 742ms app.codeStats 1ms

/Utilities/Helpers/EnumHelper.cs

#
C# | 1135 lines | 687 code | 110 blank | 338 comment | 35 complexity | a9d723da4a25ba7ca879c28315c2a931 MD5 | raw file
   1using System;
   2using System.Collections;
   3using System.Collections.Generic;
   4using System.ComponentModel;
   5using System.Globalization;
   6using System.Reflection;
   7using NUnit.Framework;
   8
   9namespace Delta.Utilities.Helpers
  10{
  11	/// <summary>
  12	/// Enum helper class, allows extracting Description attributes, which is
  13	/// useful for displaying name of enum and stuff. Also useful because
  14	/// Descriptions don't get obfuscated and EnumHelper has extra operations,
  15	/// like GetSize to get the number of elements an enum uses.
  16	/// </summary>
  17	public static class EnumHelper
  18	{
  19		#region EnumEnumerator Class
  20		/// <summary>
  21		/// Enum enumerator helper for GetEnumerator,
  22		/// this allow us to enumerate enums just like collections
  23		/// </summary>
  24		public class EnumEnumerator
  25			: IEnumerator, IEnumerable
  26		{
  27			#region EnumType (Public)
  28			/// <summary>
  29			/// The enum we use
  30			/// </summary>
  31			public Type EnumType;
  32			#endregion
  33
  34			#region index (Public)
  35			/// <summary>
  36			/// Own index
  37			/// </summary>
  38			public int index;
  39			#endregion
  40
  41			#region EnumCount (Public)
  42			/// <summary>
  43			/// Count of enum values.
  44			/// </summary>
  45			/// <returns>Int</returns>
  46			public int EnumCount
  47			{
  48				get
  49				{
  50					return enumValues.Length;
  51				}
  52			}
  53			#endregion
  54
  55			#region Current (Public)
  56			/// <summary>
  57			/// Current enum value
  58			/// </summary>
  59			public object Current
  60			{
  61				get
  62				{
  63					if (index >= 0 &&
  64					    index < EnumCount)
  65					{
  66						return enumValues.GetValue(index);
  67					}
  68					else
  69					{
  70						// Just return first entry if index is invalid
  71						return enumValues.GetValue(0);
  72					}
  73				}
  74			}
  75			#endregion
  76
  77			#region Private
  78
  79			#region enumValues (Private)
  80			/// <summary>
  81			/// Enum values
  82			/// </summary>
  83			private readonly Array enumValues;
  84			#endregion
  85
  86			#endregion
  87
  88			#region Constructors
  89			/// <summary>
  90			/// Create enum enumerator
  91			/// </summary>
  92			/// <param name="setEnumType">Enum type</param>
  93			public EnumEnumerator(Type setEnumType)
  94			{
  95				EnumType = setEnumType;
  96				index = -1;
  97				enumValues = Enum.GetValues(EnumType);
  98			}
  99			#endregion
 100
 101			#region IEnumerable Members
 102			/// <summary>
 103			/// Get enumerator
 104			/// </summary>
 105			/// <returns>Enumerator to enumerate with</returns>
 106			public IEnumerator GetEnumerator()
 107			{
 108				return this;
 109			}
 110			#endregion
 111
 112			#region IEnumerator Members
 113			/// <summary>
 114			/// Move next
 115			/// </summary>
 116			public bool MoveNext()
 117			{
 118				index++;
 119				// Finished?
 120				return index < EnumCount;
 121			}
 122
 123			/// <summary>
 124			/// Reset
 125			/// </summary>
 126			public void Reset()
 127			{
 128				index = -1;
 129			}
 130			#endregion
 131		}
 132		#endregion
 133
 134		#region GetCount (Static)
 135		/// <summary>
 136		/// Gets the number of elements for the given Enum type.
 137		/// </summary>
 138		/// <typeparam name="T">Type of enum</typeparam>
 139		/// <returns>Number of possible enum elements</returns>
 140		public static int GetCount<T>()
 141		{
 142			Type enumType = typeof(T);
 143			if (enumType.IsEnum)
 144			{
 145				return Enum.GetValues(enumType).Length;
 146			}
 147			
 148			Log.Warning(
 149				"EnumHelper.GetCount: The given type=" + enumType + " isn't a " +
 150				"valid enum!");
 151			return 0;
 152		}
 153
 154		/// <summary>
 155		/// Gets the number of elements for the given Enum type.
 156		/// </summary>
 157		/// <param name="anyEnum">Any enum value</param>
 158		/// <returns>Number of enum values in this given enum</returns>
 159		public static int GetCount(this Enum anyEnum)
 160		{
 161			Type enumType = anyEnum.GetType();
 162			if (enumType.IsEnum)
 163			{
 164				return Enum.GetValues(enumType).Length;
 165			}
 166
 167			Log.Warning(
 168				"EnumHelper.GetCount: The given type=" + enumType + " isn't a valid " +
 169				"enum!");
 170			return 0;
 171		}
 172		#endregion
 173
 174		#region NextValue (Static)
 175		/// <summary>
 176		/// Get the next enum value in any given enum.
 177		/// </summary>
 178		/// <typeparam name="T">Type for this enum</typeparam>
 179		/// <param name="enumValue">Enum type</param>
 180		/// <returns>Next enum value</returns>
 181		public static T NextValue<T>(this T enumValue)
 182			where T : IConvertible
 183		{
 184			// At first we determine the type
 185			Type enumType = typeof(T);
 186			// to look if the given object is really an Enum
 187			if (enumType.IsEnum == false)
 188			{
 189				// if not, we log a warning
 190				Log.Warning(
 191					"EnumHelper.NextValue: The given type=" + enumType + " isn't a " +
 192					"valid enum!");
 193				// and just return the given value back...
 194				return enumValue;
 195			}
 196
 197			// To know which is the current value of the enum, we just iterate
 198			// through all of them (in worst case)
 199			Array enumValues = Enum.GetValues(enumType);
 200			int foundIndex = MathHelper.InvalidIndex;
 201			for (int i = 0; i < enumValues.Length; i++)
 202			{
 203				// If we have found it (which occurs every time sooner or later)
 204				if (enumValues.GetValue(i).Equals(enumValue))
 205				{
 206					// we "compute" the index of the next value, which is just the next
 207					// index or the first index, if the current value is the last one
 208					// -> cycling
 209					foundIndex =
 210						i == enumValues.Length - 1
 211							? 0
 212							: i + 1;
 213					break;
 214				}
 215			}
 216
 217			return (T)enumValues.GetValue(foundIndex);
 218		}
 219		#endregion
 220
 221		#region ToUInt64 (Static)
 222		/// <summary>
 223		/// Converts given enum into unsigned long
 224		/// </summary>
 225		/// <param name="enumValue">Enum value to convert</param>
 226		/// <returns>Unsigned long value created from this enum value</returns>
 227		/// <exception cref="InvalidOperationException">
 228		/// Invalid internal enum type
 229		/// </exception>
 230		public static ulong ToUInt64(this Enum enumValue)
 231		{
 232			switch (enumValue.GetTypeCode())
 233			{
 234				case TypeCode.SByte:
 235				case TypeCode.Int16:
 236				case TypeCode.Int32:
 237				case TypeCode.Int64:
 238					return (ulong)Convert.ToInt64(enumValue,
 239						CultureInfo.InvariantCulture);
 240
 241				case TypeCode.Byte:
 242				case TypeCode.UInt16:
 243				case TypeCode.UInt32:
 244				case TypeCode.UInt64:
 245					return Convert.ToUInt64(enumValue, CultureInfo.InvariantCulture);
 246			}
 247
 248			throw new InvalidOperationException("Invalid internal enum type");
 249		}
 250		#endregion
 251
 252		#region ToInt (Static)
 253		/// <summary>
 254		/// Converts given enum into int
 255		/// </summary>
 256		/// <param name="enumValue">Enum value to convert</param>
 257		/// <returns>Integer value created from this enum value</returns>
 258		/// <exception cref="InvalidOperationException"></exception>
 259		public static int ToInt(this Enum enumValue)
 260		{
 261			TypeCode typeCode = enumValue.GetTypeCode();
 262			switch (typeCode)
 263			{
 264				case TypeCode.SByte:
 265				case TypeCode.Int16:
 266				case TypeCode.Int32:
 267				case TypeCode.Byte:
 268				case TypeCode.UInt16:
 269					return Convert.ToInt32(enumValue, CultureInfo.InvariantCulture);
 270
 271				case TypeCode.UInt32:
 272				case TypeCode.Int64:
 273				case TypeCode.UInt64:
 274					Log.Warning(
 275						"You are converting an enum with internal type of " + typeCode +
 276						" to an Int32. This may yield wrong results, so use ToUInt64 " +
 277						"instead.");
 278					return Convert.ToInt32(enumValue, CultureInfo.InvariantCulture);
 279			}
 280
 281			throw new InvalidOperationException(
 282				"Invalid internal enum type: " + typeCode);
 283		}
 284		#endregion
 285
 286		#region IsFlagSet (Static)
 287		/// <summary>
 288		/// Checks if given Enum has given flag set. If the enum does not use
 289		/// flags, this method should not be used.
 290		/// </summary>
 291		/// <param name="combinedEnum">Combined enum value</param>
 292		/// <param name="flag">Flag to check</param>
 293		/// <returns>True if the enum flag is set, false otherwise.</returns>
 294		public static bool IsFlagSet(this Enum combinedEnum, Enum flag)
 295		{
 296			return combinedEnum.HasFlag(flag);
 297		}
 298		#endregion
 299
 300		#region ToEnum (Static)
 301		/// <summary>
 302		/// Simple implementation which replaces all other Enum conversion methods.
 303		/// Works with: String names, string numbers, Combined enums (comma
 304		/// separated, or as number string), Irregular numbered ones.
 305		/// It returns default enum value, if there is no match.
 306		/// </summary>
 307		/// <typeparam name="T">Type of enum to parse</typeparam>
 308		/// <param name="enumName">
 309		/// Enum string to convert (can be a number, a string, a comma separated 
 310		/// combination or a combined number)
 311		/// </param>
 312		/// <returns>
 313		/// Enum type parsed or the default value if parsing was not possible
 314		/// </returns>
 315		public static T ToEnum<T>(this string enumName)
 316		{
 317			try
 318			{
 319				return
 320					String.IsNullOrEmpty(enumName)
 321						? default(T)
 322						: (T)Enum.Parse(typeof(T), enumName, false);
 323			}
 324			catch (Exception)
 325			{
 326				return default(T);
 327			}
 328		}
 329
 330		/// <summary>
 331		/// Simple implementation which replaces all other Enum conversion methods.
 332		/// Works with: String names, string numbers, Combined enums (comma
 333		/// separated, or as number string), Irregular numbered ones.
 334		/// It returns default enum value, if there is no match.
 335		/// </summary>
 336		/// <typeparam name="T">Type of enum to parse</typeparam>
 337		/// <param name="enumNames">
 338		/// Enum string array of enum values, which will be combined into one
 339		/// comma separated string and converted to an Enum.
 340		/// </param>
 341		/// <returns>
 342		/// Enum type parsed or the default value if parsing was not possible
 343		/// </returns>
 344		public static T ToEnum<T>(this string[] enumNames)
 345		{
 346			return enumNames.Write().ToEnum<T>();
 347		}
 348
 349		/// <summary>
 350		/// Simple implementation which replaces all other Enum conversion methods.
 351		/// Works with: String names, string numbers, Combined enums (comma
 352		/// separated, or as number string), Irregular numbered ones.
 353		/// It returns default enum value, if there is no match.
 354		/// </summary>
 355		/// <typeparam name="T">Type of enum to parse</typeparam>
 356		/// <param name="enumName">
 357		/// Enum string to convert (can be a number, a string, a comma separated 
 358		/// combination or a combined number)
 359		/// </param>
 360		/// <param name="result">
 361		/// Enum type parsed or the default value if parsing was not possible
 362		/// </param>
 363		/// <returns>True if the enum value was found, false otherwise</returns>
 364		public static bool ToEnum<T>(this string enumName, out T result)
 365		{
 366			if (String.IsNullOrEmpty(enumName))
 367			{
 368				// Special case: treat empty string as default value
 369				result = default(T);
 370				return true;
 371			}
 372			try
 373			{
 374				result = (T)Enum.Parse(typeof(T), enumName, false);
 375				return true;
 376			}
 377			catch (Exception)
 378			{
 379				result = default(T);
 380				return false;
 381			}
 382		}
 383		#endregion
 384
 385		#region GetEnumIndex (Static)
 386		/// <summary>
 387		/// Get enum index from value. If we use a known enum, we could simply
 388		/// write (int)SomeEnum.Value, but we can't do that with System.Enum
 389		/// we have to use in a lot of methods or if we use an auto-generated enum
 390		/// </summary>
 391		/// <param name="enumValue">Enum value</param>
 392		/// <returns>
 393		/// Index of the enum value, which is normally the enum value,
 394		/// but if the enum uses custom values for each enum, it is not the same!
 395		/// </returns>
 396		public static int GetEnumIndex(this Enum enumValue)
 397		{
 398			string[] enumNames = Enum.GetNames(enumValue.GetType());
 399
 400			for (int num = 0; num < enumNames.Length; num++)
 401			{
 402				if (enumValue.ToString() == enumNames[num])
 403				{
 404					return num;
 405				}
 406			}
 407
 408			// If not found, just return maxValue + 1. Don't throw any exception
 409			return enumNames.Length;
 410		}
 411		#endregion
 412
 413		#region SelectNextEnum (Static)
 414		/// <summary>
 415		/// Select next enum
 416		/// </summary>
 417		/// <param name="enumValue">Enum</param>
 418		/// <returns>Next enum value</returns>
 419		public static Enum SelectNextEnum(this Enum enumValue)
 420		{
 421			Array enumValues = Enum.GetValues(enumValue.GetType());
 422
 423			// Select next enum value
 424			int valueIndex = (GetEnumIndex(enumValue) + 1) % GetCount(enumValue);
 425			return (Enum)enumValues.GetValue(valueIndex);
 426		}
 427		#endregion
 428
 429		#region Next (Static)
 430		/// <summary>
 431		/// Get next enum value
 432		/// </summary>
 433		/// <param name="enumValue">Enum</param>
 434		/// <returns>Next enum value</returns>
 435		public static Enum Next(this Enum enumValue)
 436		{
 437			return SelectNextEnum(enumValue);
 438		}
 439		#endregion
 440
 441		#region SelectPreviousEnum (Static)
 442		/// <summary>
 443		/// Select previous enum
 444		/// </summary>
 445		/// <param name="enumValue">Enum</param>
 446		/// <returns>Previous enum value</returns>
 447		public static Enum SelectPreviousEnum(this Enum enumValue)
 448		{
 449			Array enumValues = Enum.GetValues(enumValue.GetType());
 450
 451			// Select next enum value
 452			int valueIndex = (GetEnumIndex(enumValue) - 1) % GetCount(enumValue);
 453			if (valueIndex < 0)
 454			{
 455				valueIndex += GetCount(enumValue);
 456			}
 457			return (Enum)enumValues.GetValue(valueIndex);
 458		}
 459		#endregion
 460
 461		#region Previous (Static)
 462		/// <summary>
 463		/// Get previous enum value
 464		/// </summary>
 465		/// <param name="enumValue">Enum</param>
 466		/// <returns>Previous enum value</returns>
 467		public static Enum Previous(this Enum enumValue)
 468		{
 469			return SelectPreviousEnum(enumValue);
 470		}
 471		#endregion
 472
 473		#region GetValues (Static)
 474		/// <summary>
 475		/// Returns all values of the given enum, which is severy single possible
 476		/// enum value as an array of enum values. For more details see:
 477		/// http://www.dolittle.no/blogs/einar/archive/2008/01/13/missing-enum-getvalues-when-doing-silverlight-for-instance.aspx
 478		/// </summary>
 479		public static T[] GetValues<T>()
 480		{
 481			Type enumType = typeof(T);
 482
 483			#region Validation
 484			if (enumType.IsEnum == false)
 485			{
 486				Log.Warning("The given type '" + enumType + "' isn't an enum");
 487				return new T[0];
 488			}
 489			#endregion
 490
 491			List<T> values = new List<T>();
 492			foreach (FieldInfo field in enumType.GetFields())
 493			{
 494				if (field.IsLiteral)
 495				{
 496					T value = (T)field.GetValue(enumType);
 497					values.Add(value);
 498				}
 499			}
 500
 501			return values.ToArray();
 502		}
 503
 504		/// <summary>
 505		/// Returns all values of the given enum, which is severy single possible
 506		/// enum value as an array of enum values. For more details see:
 507		/// http://www.dolittle.no/blogs/einar/archive/2008/01/13/missing-enum-getvalues-when-doing-silverlight-for-instance.aspx
 508		/// </summary>
 509		/// <param name="enumType">Some enum type</param>
 510		/// <returns>Array of enum values</returns>
 511		public static Enum[] GetValues(this Type enumType)
 512		{
 513			#region Validation
 514			if (enumType.IsEnum == false)
 515			{
 516				Log.Warning("The given type '" + enumType + "' isn't an enum");
 517				return new Enum[0];
 518			}
 519			#endregion
 520
 521			List<Enum> values = new List<Enum>();
 522			foreach (FieldInfo field in enumType.GetFields())
 523			{
 524				if (field.IsLiteral)
 525				{
 526					object value = field.GetValue(enumType);
 527					values.Add((Enum)value);
 528				}
 529			}
 530
 531			return values.ToArray();
 532		}
 533		#endregion
 534
 535		#region GetNames (Static)
 536		/// <summary>
 537		/// Returns the names for all enum values, which is severy single possible
 538		/// enum value as a string array. For more details see:
 539		/// http://stackoverflow.com/questions/1038234/iterating-through-an-enumeration-in-silverlight
 540		/// </summary>
 541		/// <typeparam name="T">Type of enum</typeparam>
 542		/// <returns>List of strings with the enum names</returns>
 543		public static string[] GetNames<T>()
 544		{
 545			return GetNames(typeof(T));
 546		}
 547
 548		/// <summary>
 549		/// Returns the names for all enum values, which is severy single possible
 550		/// enum value as a string array. For more details see:
 551		/// http://stackoverflow.com/questions/1038234/iterating-through-an-enumeration-in-silverlight
 552		/// </summary>
 553		/// <param name="enumType">Some enum type</param>
 554		/// <returns>List of strings with the enum names</returns>
 555		public static string[] GetNames(Type enumType)
 556		{
 557			#region Validation
 558			if (enumType.IsEnum == false)
 559			{
 560				Log.Warning("The given type '" + enumType + "' isn't an enum");
 561				return new string[0];
 562			}
 563			#endregion
 564
 565			List<string> values = new List<string>();
 566			foreach (FieldInfo field in enumType.GetFields())
 567			{
 568				if (field.IsLiteral)
 569				{
 570					values.Add(field.Name);
 571				}
 572			}
 573
 574			return values.ToArray();
 575		}
 576		#endregion
 577
 578		#region GetEnumerator (Static)
 579		/// <summary>
 580		/// Get enumerator
 581		/// </summary>
 582		/// <returns>Enumerator for enumeration (foreach, etc.)</returns>
 583		public static EnumEnumerator GetEnumerator(Type enumType)
 584		{
 585			return new EnumEnumerator(enumType);
 586		}
 587		#endregion
 588
 589		#region GetEnumDescription (Static)
 590		/// <summary>
 591		/// Gets enum value Description Attribute
 592		/// </summary>
 593		/// <param name="value">
 594		/// The value you want the description attribute for
 595		/// </param>
 596		/// <returns>The description, if any, else it's value.ToString()</returns>
 597		public static string GetEnumDescription(this Enum value)
 598		{
 599			FieldInfo field = value.GetType().GetField(value.ToString());
 600			if (field != null)
 601			{
 602				DescriptionAttribute[] attributes =
 603					(DescriptionAttribute[])field.GetCustomAttributes(
 604						typeof(DescriptionAttribute), false);
 605				return
 606					attributes.Length > 0
 607						? attributes[0].Description
 608						: value.ToString();
 609			}
 610
 611			// If that fails, just use enum name
 612			return value.ToString();
 613		}
 614		#endregion
 615
 616		#region Description (Static)
 617		/// <summary>
 618		/// Helper method to get an enum description attribute from a specific enum
 619		/// value as a string.
 620		/// </summary>
 621		/// <param name="value">Enum value</param>
 622		/// <returns>
 623		/// Description text if available, otherwise just the enum name.
 624		/// </returns>
 625		public static string Description(this Enum value)
 626		{
 627			return GetEnumDescription(value);
 628		}
 629		#endregion
 630
 631		#region GetEnumDescription (Static)
 632		/// <summary>
 633		/// Gets the description for a certain named value in an enum
 634		/// </summary>
 635		/// <param name="value">The type of the enum</param>
 636		/// <param name="name">The name of the enum value</param>
 637		/// <returns>The description, if any, else the passed name</returns>
 638		public static string GetEnumDescription(Type value, string name)
 639		{
 640			FieldInfo fi = value.GetField(name);
 641			if (fi != null)
 642			{
 643				DescriptionAttribute[] attributes =
 644					(DescriptionAttribute[])fi.GetCustomAttributes(
 645						typeof(DescriptionAttribute), false);
 646				return attributes.Length > 0
 647				       	? attributes[0].Description
 648				       	: name;
 649			}
 650			// If that fails, just use name
 651			return name;
 652		}
 653		#endregion
 654
 655		#region GetAllEnumDescriptions (Static)
 656		/// <summary>
 657		/// Get all enum descriptions as string array, useful for
 658		/// Controls.DrawDropDownList(...)
 659		/// </summary>
 660		public static string[] GetAllEnumDescriptions(Type enumType)
 661		{
 662			;
 663			EnumEnumerator enumerator = GetEnumerator(enumType);
 664			string[] descArray = new string[enumerator.EnumCount];
 665
 666			foreach (Enum enumValue in enumerator)
 667			{
 668				descArray[enumerator.index] =
 669					GetEnumDescription(enumValue);
 670			}
 671
 672			return descArray;
 673		}
 674
 675		/// <summary>
 676		/// Get all enum descriptions as string array, useful for
 677		/// Controls.DrawDropDownList(...)
 678		/// </summary>
 679		/// <param name="value">Enum value</param>
 680		/// <returns>List of enum descriptions (if there are any)</returns>
 681		public static string[] GetAllEnumDescriptions(this Enum value)
 682		{
 683			return GetAllEnumDescriptions(value.GetType());
 684		}
 685		#endregion
 686
 687		#region GetEnumValue (Static)
 688		/// <summary>
 689		/// Gets the value of an enum, based on its Description Attribute or
 690		/// named value.
 691		/// </summary>
 692		/// <param name="value">The enum type</param>
 693		/// <param name="description">The description or name of the element
 694		/// </param>
 695		/// <returns>The value, or the passed in description, if it was not found
 696		/// </returns>
 697		public static object GetEnumValue(Type value, string description)
 698		{
 699			FieldInfo[] fis = value.GetFields();
 700			foreach (FieldInfo fi in fis)
 701			{
 702				DescriptionAttribute[] attributes =
 703					(DescriptionAttribute[])fi.GetCustomAttributes(
 704						typeof(DescriptionAttribute), false);
 705
 706				if ((attributes.Length > 0 &&
 707				     attributes[0].Description == description) ||
 708				    fi.Name == description)
 709				{
 710					return fi.GetValue(fi.Name);
 711				}
 712			}
 713
 714			return description;
 715		}
 716		#endregion
 717
 718		#region ToStringArray
 719		/// <summary>
 720		/// Get the combined enum values back as a string array. Makes only sense
 721		/// for combined enums as normal enums will just return one entry and you
 722		/// could just use ToString to get to that.
 723		/// </summary>
 724		/// <param name="value">Combined enum value</param>
 725		/// <returns>
 726		/// String array with all the selected enum values as names. You can use
 727		/// ToEnum to convert the string array back to a combined enum.
 728		/// </returns>
 729		public static string[] ToStringArray(this Enum value)
 730		{
 731			return value.ToString().SplitAndTrim(',');
 732		}
 733		#endregion
 734
 735		#region SplitCombinedEnum
 736		/// <summary>
 737		/// Get the combined enum values back as an enum list. Makes only sense
 738		/// for combined enums as normal enums will just return one entry and you
 739		/// could just use the value itself.
 740		/// </summary>
 741		/// <param name="value">Combined enum value</param>
 742		/// <returns>
 743		/// List with all the selected enum values (flags) that were used to build
 744		/// this combined enum.
 745		/// </returns>
 746		public static List<T> SplitCombinedEnum<T>(this T value)
 747			where T : IConvertible
 748		{
 749			// Make sure we got a valid enum
 750			if (value is Enum == false)
 751			{
 752				Log.Warning(
 753					"EnumHelper.SplitCombinedEnum: The given type=" + value + " isn't " +
 754					"a enum, unable to split it!");
 755				// And just return the given value back...
 756				return new List<T>(new T[]
 757				{
 758					value
 759				});
 760			}
 761
 762			string[] enumTexts = (value as Enum).ToStringArray();
 763			List<T> ret = new List<T>();
 764			if (enumTexts.Length > 1)
 765			{
 766				foreach (string enumText in enumTexts)
 767				{
 768					ret.Add(EnumHelper.ToEnum<T>(enumText));
 769				}
 770				return ret;
 771			}
 772
 773			// No combined enum, just return the current value
 774			ret.Add(value);
 775			return ret;
 776		}
 777		#endregion
 778
 779		/// <summary>
 780		/// Enum helper tests
 781		/// </summary>
 782		public class EnumHelperTests
 783		{
 784			#region Helpers
 785			/// <summary>
 786			/// Test enum
 787			/// </summary>
 788			private enum TestEnum
 789			{
 790				[Description("Some entry")]
 791				SomeEntry,
 792
 793				[Description("Another one")]
 794				AnotherOne,
 795
 796				[Description("Hey stop it now")]
 797				HeyStopItNow,
 798
 799				[Description("Okay okay")]
 800				OkayOkay,
 801			}
 802			#endregion
 803
 804			#region Helpers
 805			/// <summary>
 806			/// Flag enum
 807			/// </summary>
 808			[Flags]
 809			private enum FlagEnum : ulong
 810			{
 811				Flag1 = 1,
 812
 813				Flag2 = 2,
 814
 815				Flag3 = 4,
 816
 817				Flag4 = 8,
 818
 819				FlagUint64 = 1 << 48,
 820			}
 821			#endregion
 822
 823			#region Helpers
 824			/// <summary>
 825			/// Test combined enum
 826			/// </summary>
 827			[Flags]
 828			private enum TestCombinedEnum
 829			{
 830				Zero = 0,
 831
 832				NumberOne = 1,
 833
 834				NumberTwo = 2,
 835
 836				NumberFour = 4,
 837			}
 838			#endregion
 839
 840			#region TestEnumStuff (Static)
 841			/// <summary>
 842			/// Test enum stuff. Note: Too slow for a dynamic unit test.
 843			/// </summary>
 844			[Test]
 845			public static void TestEnumStuff()
 846			{
 847				//// First get size of TestEnum (with type of enum)
 848				//Assert.Equal(GetSize(typeof(TestEnum)), 4);
 849				//Assert.Equal(typeof(TestEnum).GetSize(), 4);
 850
 851				//// Now try with some enum member (should give the same result)
 852				//Assert.Equal(GetSize(TestEnum.SomeEntry), 4);
 853
 854				// Test with extension
 855				Assert.Equal(TestEnum.SomeEntry.GetCount(), 4);
 856				Assert.Equal(TestEnum.SomeEntry.GetCount(), 4);
 857
 858				// Try to get enum from name
 859				Assert.Equal(TestEnum.OkayOkay,
 860					"OkayOkay".ToEnum<TestEnum>());
 861
 862				// Get description of an enum members
 863				Assert.Equal(GetEnumDescription(TestEnum.OkayOkay), "Okay okay");
 864				Assert.Equal(TestEnum.OkayOkay.Description(), "Okay okay");
 865
 866				// Test enum enumerator stuff
 867				string allEnumNames = GetEnumerator(typeof(TestEnum)).Write();
 868				Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay",
 869					allEnumNames);
 870
 871				// Test same with description values
 872				string allEnumDescNames = "";
 873				foreach (TestEnum enumValue in
 874					GetEnumerator(typeof(TestEnum)))
 875				{
 876					allEnumDescNames += (allEnumDescNames.Length == 0
 877					                     	? ""
 878					                     	: ", ") +
 879					                    GetEnumDescription(enumValue);
 880				}
 881				Assert.Equal(
 882					"Some entry, Another one, Hey stop it now, Okay okay",
 883					allEnumDescNames);
 884
 885				// Same check with GetAllEnumDescriptions
 886				Assert.Equal(
 887					"Some entry, Another one, Hey stop it now, Okay okay",
 888					GetAllEnumDescriptions(typeof(TestEnum)).Write());
 889			}
 890			#endregion
 891
 892			#region TestNextAndPreviousEnum (Static)
 893			/// <summary>
 894			/// Test next and previous enum. Note: Too slow for a dynamic unit test.
 895			/// </summary>
 896			[Test]
 897			public static void TestNextAndPreviousEnum()
 898			{
 899				TestEnum someEnum = TestEnum.SomeEntry;
 900				Assert.Equal(TestEnum.SomeEntry, someEnum);
 901
 902				// Check next entry
 903				someEnum = (TestEnum)someEnum.SelectNextEnum();
 904				Assert.Equal(TestEnum.AnotherOne, someEnum);
 905				Assert.Equal(TestEnum.AnotherOne, TestEnum.SomeEntry.Next());
 906
 907				// Go back 2 entries, this will select the last enum entry
 908				someEnum = (TestEnum)someEnum.SelectPreviousEnum();
 909				someEnum = (TestEnum)someEnum.SelectPreviousEnum();
 910				Assert.Equal(TestEnum.OkayOkay, someEnum);
 911				Assert.Equal(TestEnum.AnotherOne, TestEnum.HeyStopItNow.Previous());
 912			}
 913			#endregion
 914
 915			#region TestGetAllEnumValues (Static)
 916			/// <summary>
 917			/// Test get all enum values. Note: Too slow for a dynamic unit test.
 918			/// </summary>
 919			[Test]
 920			public static void TestGetAllEnumValues()
 921			{
 922				// Test with type
 923				TestEnum[] enums = GetValues<TestEnum>();
 924				Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay",
 925					enums.Write());
 926
 927				// Create with instance
 928				string[] inputEnumNames = new[]
 929				{
 930					"SomeEntry",
 931					"AnotherOne",
 932					"HeyStopItNow",
 933					"OkayOkay",
 934				};
 935
 936				//This code needs reflection, not supported right now in DE:
 937				//enums = GetAllEnumValues(CreateEnum(inputEnumNames).GetType());
 938			  //Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay",
 939			  //  ArrayHelper.Write(enums));
 940			}
 941			#endregion
 942			
 943			#region GetValues (Static)
 944			/// <summary>
 945			/// Get values
 946			/// </summary>
 947			[Test]
 948			public static void GetValues()
 949			{
 950				object[] values = typeof(StringSplitOptions).GetValues();
 951				Assert.Equal(values.Length, 2);
 952				Assert.Equal(values[0], StringSplitOptions.None);
 953				Assert.Equal(values[1], StringSplitOptions.RemoveEmptyEntries);
 954
 955				StringSplitOptions[] genericValues =
 956					GetValues<StringSplitOptions>();
 957				Assert.Equal(genericValues.Length, 2);
 958				Assert.Equal(genericValues[0], StringSplitOptions.None);
 959				Assert.Equal(genericValues[1], StringSplitOptions.RemoveEmptyEntries);
 960			}
 961			#endregion
 962
 963			#region GetNames (Static)
 964			/// <summary>
 965			/// Get names
 966			/// </summary>
 967			[Test]
 968			public static void GetNames()
 969			{
 970				string[] names = EnumHelper.GetNames(typeof(StringSplitOptions));
 971				Assert.Equal(names.Length, 2);
 972				Assert.Equal(names[0], "None");
 973				Assert.Equal(names[1], "RemoveEmptyEntries");
 974
 975				string[] genericNames = GetNames<StringSplitOptions>();
 976				Assert.Equal(genericNames.Length, 2);
 977				Assert.Equal(genericNames[0], "None");
 978				Assert.Equal(genericNames[1], "RemoveEmptyEntries");
 979			}
 980			#endregion
 981
 982			#region ConvertToNumberWithCombinedEnum (LongRunning)
 983			/// <summary>
 984			/// Convert to number
 985			/// </summary>
 986			[Test]
 987			public void ConvertToNumberWithCombinedEnum()
 988			{
 989				// Reproduce test with standard methods
 990				Assert.Equal(4, (int)"NumberFour".ToEnum<TestCombinedEnum>());
 991				Assert.Equal(6,
 992					(int)"NumberTwo, NumberFour".ToEnum<TestCombinedEnum>());
 993				Assert.Equal(
 994					(int)(TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour),
 995					(int)"6".ToEnum<TestCombinedEnum>());
 996				Assert.Equal("NumberTwo, NumberFour",
 997					(TestCombinedEnum.NumberTwo |
 998					 TestCombinedEnum.NumberFour).ToString());
 999				Assert.Equal(TestCombinedEnum.Zero, "bla".ToEnum<TestCombinedEnum>());
1000				Assert.Equal("Zero", TestCombinedEnum.Zero.ToString());
1001
1002				Assert.Equal(0,
1003					(int)(TestCombinedEnum.Zero.ToString().
1004					     	ToEnum<TestCombinedEnum>()));
1005				Assert.Equal(
1006					(int)(TestCombinedEnum.NumberTwo |
1007					      TestCombinedEnum.NumberFour),
1008					(int)(TestCombinedEnum.NumberTwo |
1009					      TestCombinedEnum.NumberFour.ToString().
1010					      	ToEnum<TestCombinedEnum>()));
1011
1012				// Finally write down a combined enum.
1013				TestCombinedEnum combinedValue =
1014					TestCombinedEnum.NumberTwo |
1015					TestCombinedEnum.NumberFour;
1016				Assert.Equal("NumberTwo, NumberFour", combinedValue.ToString());
1017				Assert.Equal(combinedValue.ToStringArray(), new string[]
1018				{
1019					"NumberTwo", "NumberFour"
1020				});
1021				// This can be useful to build a combined enum name as a filename!
1022				Assert.Equal(combinedValue.ToStringArray().Write("_"),
1023					"NumberTwo_NumberFour");
1024				Assert.Equal(combinedValue,
1025					combinedValue.ToStringArray().ToEnum<TestCombinedEnum>());
1026			}
1027			#endregion
1028
1029			#region GetCount
1030			/// <summary>
1031			/// Get count
1032			/// </summary>
1033			[Test]
1034			public void GetCount()
1035			{
1036				Assert.Equal(7, GetCount<DayOfWeek>());
1037			}
1038			#endregion
1039
1040			#region NextValue
1041			/// <summary>
1042			/// Next value
1043			/// </summary>
1044			[Test]
1045			public void NextValue()
1046			{
1047				Assert.Equal(DayOfWeek.Monday, DayOfWeek.Sunday.NextValue());
1048			}
1049			#endregion
1050
1051			#region ToEnum
1052			/// <summary>
1053			/// Get enum from name
1054			/// </summary>
1055			[Test]
1056			public void ToEnum()
1057			{
1058				// Standard Enum
1059				Assert.Equal(FlagEnum.Flag2, "Flag2".ToEnum<FlagEnum>());
1060
1061				// Combined Enum
1062				Assert.Equal(FlagEnum.Flag1 | FlagEnum.Flag3,
1063					"Flag1, Flag3".ToEnum<FlagEnum>());
1064				Assert.Equal(FlagEnum.Flag2 | FlagEnum.Flag4,
1065					"Flag4, Flag2".ToEnum<FlagEnum>());
1066
1067				// Number to Enum
1068				Assert.Equal(FlagEnum.Flag3,
1069					"4".ToEnum<FlagEnum>());
1070
1071				// Number to combined Enum
1072				Assert.Equal(FlagEnum.Flag2 | FlagEnum.Flag4,
1073					"10".ToEnum<FlagEnum>());
1074			}
1075			#endregion
1076
1077			#region FlagTests
1078			/// <summary>
1079			/// Flag tests
1080			/// </summary>
1081			[Test]
1082			public void FlagTests()
1083			{
1084				Assert.Equal(2,
1085					(int)("NumberTwo, NumberFour".ToEnum<TestCombinedEnum>() &
1086					      TestCombinedEnum.NumberTwo));
1087			}
1088			#endregion
1089
1090			#region ConvertToInteger
1091			/// <summary>
1092			/// ConvertToInteger test
1093			/// </summary>
1094			[Test]
1095			public void ConvertToInteger()
1096			{
1097				// Test with int
1098				Assert.Equal(2, TestCombinedEnum.NumberTwo.ToInt());
1099				Assert.Equal(6,
1100					(TestCombinedEnum.NumberFour |
1101					 TestCombinedEnum.NumberTwo).ToInt());
1102
1103				// Test with UInt64
1104				Assert.Equal<ulong>(1 << 48, FlagEnum.FlagUint64.ToUInt64());
1105
1106				// This should warn about possible overflows
1107				Assert.Equal(4, FlagEnum.Flag3.ToInt());
1108			}
1109			#endregion
1110
1111			#region ToInt
1112			/// <summary>
1113			/// Convert to number
1114			/// </summary>
1115			[Test]
1116			public void ToInt()
1117			{
1118				Assert.Equal(0,
1119				  EnumHelper.ToInt(TestCombinedEnum.Zero));
1120				Assert.Equal(2,
1121					EnumHelper.ToInt(TestCombinedEnum.NumberTwo));
1122
1123				Assert.Equal(4,
1124					EnumHelper.ToInt(TestCombinedEnum.NumberFour));
1125				Assert.Equal(6, EnumHelper.ToInt(
1126					TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour));
1127				Assert.Equal(TestCombinedEnum.NumberFour,
1128					EnumHelper.ToEnum<TestCombinedEnum>("4"));
1129				Assert.Equal(TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour,
1130					EnumHelper.ToEnum<TestCombinedEnum>("6"));
1131			}
1132			#endregion
1133		}
1134	}
1135}