PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Helpers/EnumHelper.cs

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