The Labs \ Source Viewer \ SSCLI \ System \ HashEntry

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. using System.Reflection;
  16. using System.Text;
  17. using System.Collections;
  18. using System.Globalization;
  19. using System.Runtime.CompilerServices;
  20. using System.Reflection.Emit;
  21. namespace System
  22. {
  23.     [Serializable()]
  24.     [System.Runtime.InteropServices.ComVisible(true)]
  25.     public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
  26.     {
  27.         #region Private Static Data Members
  28.         private static char[] enumSeperatorCharArray = new char[] {','};
  29.         private const string enumSeperator = ", ";
  30.         private static Type intType = typeof(int);
  31.         private static Type stringType = typeof(string);
  32.         private static Hashtable fieldInfoHash = Hashtable.Synchronized(new Hashtable());
  33.         private const int maxHashElements = 100;
  34.         // to trim the working set
  35.         #endregion
  36.         #region Private Static Methods
  37.         private static FieldInfo GetValueField(Type type)
  38.         {
  39.             FieldInfo[] flds;
  40.            
  41.             flds = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  42.            
  43.             if ((flds == null) || (flds.Length != 1))
  44.                 throw new ArgumentException(Environment.GetResourceString("Arg_EnumMustHaveUnderlyingValueField"));
  45.            
  46.             return flds[0];
  47.         }
  48.        
  49.         private static HashEntry GetHashEntry(Type enumType)
  50.         {
  51.             HashEntry hashEntry = (HashEntry)fieldInfoHash[enumType];
  52.            
  53.             if (hashEntry == null) {
  54.                 // To reduce the workingset we clear the hashtable when a threshold number of elements are inserted.
  55.                 if (fieldInfoHash.Count > maxHashElements)
  56.                     fieldInfoHash.Clear();
  57.                
  58.                 ulong[] values = null;
  59.                 string[] names = null;
  60.                
  61.                 BCLDebug.Assert(enumType.BaseType == typeof(Enum), "Base type must of type Enum");
  62.                 if (enumType.BaseType == typeof(Enum))
  63.                     InternalGetEnumValues(enumType, ref values, ref names);
  64.                 // If we switch over to EnumBuilder, this code path will be required.
  65.                 else {
  66.                     // fall back on reflection for odd cases
  67.                     FieldInfo[] flds = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
  68.                    
  69.                     values = new ulong[flds.Length];
  70.                     names = new string[flds.Length];
  71.                     for (int i = 0; i < flds.Length; i++) {
  72.                         names[i] = flds[i].Name;
  73.                         values[i] = ToUInt64(flds[i].GetValue(null));
  74.                     }
  75.                    
  76.                     // Insertion Sort these values in ascending order.
  77.                     // We use this O(n^2) algorithm, but it turns out that most of the time the elements are already in sorted order and
  78.                     // the common case performance will be faster than quick sorting this.
  79.                     for (int i = 1; i < values.Length; i++) {
  80.                         int j = i;
  81.                         string tempStr = names[i];
  82.                         ulong val = values[i];
  83.                         bool exchanged = false;
  84.                        
  85.                         // Since the elements are sorted we only need to do one comparision, we keep the check for j inside the loop.
  86.                         while (values[j - 1] > val) {
  87.                             names[j] = names[j - 1];
  88.                             values[j] = values[j - 1];
  89.                             j--;
  90.                             exchanged = true;
  91.                             if (j == 0)
  92.                                 break;
  93.                         }
  94.                        
  95.                         if (exchanged) {
  96.                             names[j] = tempStr;
  97.                             values[j] = val;
  98.                         }
  99.                     }
  100.                 }
  101.                
  102.                 hashEntry = new HashEntry(names, values);
  103.                 fieldInfoHash[enumType] = hashEntry;
  104.             }
  105.            
  106.             return hashEntry;
  107.         }
  108.        
  109.         private static string InternalGetValueAsString(Type enumType, object value)
  110.         {
  111.             //Don't ask for the private fields. Only .value is private and we don't need that.
  112.             HashEntry hashEntry = GetHashEntry(enumType);
  113.             Type eT = GetUnderlyingType(enumType);
  114.            
  115.             // Lets break this up based upon the size. We'll do part as an 64bit value
  116.             // and part as the 32bit values.
  117.             if (eT == intType || eT == typeof(short) || eT == typeof(long) || eT == typeof(ushort) || eT == typeof(byte) || eT == typeof(sbyte) || eT == typeof(uint) || eT == typeof(ulong)) {
  118.                 ulong val = ToUInt64(value);
  119.                 int index = BinarySearch(hashEntry.values, val);
  120.                
  121.                 if (index >= 0)
  122.                     return hashEntry.names[index];
  123.             }
  124.            
  125.             return null;
  126.         }
  127.        
  128.         private static string InternalFormattedHexString(object value)
  129.         {
  130.             TypeCode typeCode = Convert.GetTypeCode(value);
  131.            
  132.             switch (typeCode) {
  133.                 case TypeCode.SByte:
  134.                    
  135.                     {
  136.                         byte result = (byte)(sbyte)value;
  137.                        
  138.                         return result.ToString("X2", null);
  139.                     }
  140.                     break;
  141.                 case TypeCode.Byte:
  142.                    
  143.                    
  144.                     {
  145.                         byte result = (byte)value;
  146.                        
  147.                         return result.ToString("X2", null);
  148.                     }
  149.                     break;
  150.                 case TypeCode.Int16:
  151.                    
  152.                    
  153.                     {
  154.                         UInt16 result = (UInt16)(Int16)value;
  155.                        
  156.                         return result.ToString("X4", null);
  157.                     }
  158.                     break;
  159.                 case TypeCode.UInt16:
  160.                    
  161.                    
  162.                     {
  163.                         UInt16 result = (UInt16)value;
  164.                        
  165.                         return result.ToString("X4", null);
  166.                     }
  167.                     break;
  168.                 case TypeCode.UInt32:
  169.                    
  170.                    
  171.                     {
  172.                         UInt32 result = (UInt32)value;
  173.                        
  174.                         return result.ToString("X8", null);
  175.                     }
  176.                     break;
  177.                 case TypeCode.Int32:
  178.                    
  179.                    
  180.                     {
  181.                         UInt32 result = (UInt32)(int)value;
  182.                        
  183.                         return result.ToString("X8", null);
  184.                     }
  185.                     break;
  186.                 case TypeCode.UInt64:
  187.                    
  188.                    
  189.                     {
  190.                         UInt64 result = (UInt64)value;
  191.                        
  192.                         return result.ToString("X16", null);
  193.                     }
  194.                     break;
  195.                 case TypeCode.Int64:
  196.                    
  197.                    
  198.                     {
  199.                         UInt64 result = (UInt64)(Int64)value;
  200.                        
  201.                         return result.ToString("X16", null);
  202.                     }
  203.                     break;
  204.                 default:
  205.                    
  206.                     // All unsigned types will be directly cast
  207.                     BCLDebug.Assert(false, "Invalid Object type in Format");
  208.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  209.                     break;
  210.             }
  211.         }
  212.        
  213.         private static string InternalFormat(Type eT, object value)
  214.         {
  215.             // Not marked with Flags attribute
  216.             if (!eT.IsDefined(typeof(System.FlagsAttribute), false)) {
  217.                 // Try to see if its one of the enum values, then we return a String back else the value
  218.                 string retval = InternalGetValueAsString(eT, value);
  219.                 if (retval == null)
  220.                     return value.ToString();
  221.                 else
  222.                     return retval;
  223.             }
  224.             // These are flags OR'ed together (We treat everything as unsigned types)
  225.             else {
  226.                 return InternalFlagsFormat(eT, value);
  227.                
  228.             }
  229.         }
  230.        
  231.         private static string InternalFlagsFormat(Type eT, object value)
  232.         {
  233.             ulong result = ToUInt64(value);
  234.             HashEntry hashEntry = GetHashEntry(eT);
  235.             // These values are sorted by value. Don't change this
  236.             string[] names = hashEntry.names;
  237.             ulong[] values = hashEntry.values;
  238.            
  239.             int index = values.Length - 1;
  240.             StringBuilder retval = new StringBuilder();
  241.             bool firstTime = true;
  242.             ulong saveResult = result;
  243.            
  244.             // We will not optimize this code further to keep it maintainable. There are some boundary checks that can be applied
  245.             // to minimize the comparsions required. This code works the same for the best/worst case. In general the number of
  246.             // items in an enum are sufficiently small and not worth the optimization.
  247.             while (index >= 0) {
  248.                 if ((index == 0) && (values[index] == 0))
  249.                     break;
  250.                
  251.                 if ((result & values[index]) == values[index]) {
  252.                     result -= values[index];
  253.                     if (!firstTime)
  254.                         retval.Insert(0, enumSeperator);
  255.                    
  256.                     retval.Insert(0, names[index]);
  257.                     firstTime = false;
  258.                 }
  259.                
  260.                 index--;
  261.             }
  262.            
  263.             // We were unable to represent this number as a bitwise or of valid flags
  264.             if (result != 0)
  265.                 return value.ToString();
  266.            
  267.             // For the case when we have zero
  268.             if (saveResult == 0) {
  269.                 if (values[0] == 0)
  270.                     return names[0];
  271.                 else
  272.                     // Zero was one of the enum values.
  273.                     return "0";
  274.             }
  275.             else
  276.                 return retval.ToString();
  277.             // Return the string representation
  278.         }
  279.        
  280.         private static ulong ToUInt64(object value)
  281.         {
  282.             // Helper function to silently convert the value to UInt64 from the other base types for enum without throwing an exception.
  283.             // This is need since the Convert functions do overflow checks.
  284.             TypeCode typeCode = Convert.GetTypeCode(value);
  285.             ulong result;
  286.            
  287.             switch (typeCode) {
  288.                 case TypeCode.SByte:
  289.                 case TypeCode.Int16:
  290.                 case TypeCode.Int32:
  291.                 case TypeCode.Int64:
  292.                     result = (UInt64)Convert.ToInt64(value, CultureInfo.InvariantCulture);
  293.                     break;
  294.                 case TypeCode.Byte:
  295.                 case TypeCode.UInt16:
  296.                 case TypeCode.UInt32:
  297.                 case TypeCode.UInt64:
  298.                    
  299.                     result = Convert.ToUInt64(value, CultureInfo.InvariantCulture);
  300.                     break;
  301.                 default:
  302.                    
  303.                     // All unsigned types will be directly cast
  304.                     BCLDebug.Assert(false, "Invalid Object type in ToUInt64");
  305.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  306.                     break;
  307.             }
  308.             return result;
  309.         }
  310.        
  311.         private static int BinarySearch(ulong[] array, ulong value)
  312.         {
  313.             int lo = 0;
  314.             int hi = array.Length - 1;
  315.            
  316.             while (lo <= hi) {
  317.                 int i = (lo + hi) >> 1;
  318.                 ulong temp = array[i];
  319.                
  320.                 if (value == temp)
  321.                     return i;
  322.                
  323.                 if (temp < value) {
  324.                     lo = i + 1;
  325.                 }
  326.                 else {
  327.                     hi = i - 1;
  328.                 }
  329.             }
  330.            
  331.             return ~lo;
  332.         }
  333.        
  334.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  335.         private static extern int InternalCompareTo(object o1, object o2);
  336.        
  337.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  338.         private static extern Type InternalGetUnderlyingType(Type enumType);
  339.        
  340.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  341.         private static extern void InternalGetEnumValues(Type enumType, ref ulong[] values, ref string[] names);
  342.        
  343.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  344.         private static extern object InternalBoxEnum(Type enumType, long value);
  345.         #endregion
  346.        
  347.         #region Public Static Methods
  348.         [System.Runtime.InteropServices.ComVisible(true)]
  349.         public static object Parse(Type enumType, string value)
  350.         {
  351.             return Parse(enumType, value, false);
  352.         }
  353.        
  354.         [System.Runtime.InteropServices.ComVisible(true)]
  355.         public static object Parse(Type enumType, string value, bool ignoreCase)
  356.         {
  357.             if (enumType == null)
  358.                 throw new ArgumentNullException("enumType");
  359.            
  360.             if (!(enumType is RuntimeType))
  361.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  362.            
  363.             if (!enumType.IsEnum)
  364.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  365.            
  366.             if (value == null)
  367.                 throw new ArgumentNullException("value");
  368.            
  369.             value = value.Trim();
  370.             if (value.Length == 0)
  371.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustContainEnumInfo"));
  372.            
  373.             // We have 2 code paths here. One if they are values else if they are Strings.
  374.             // values will have the first character as as number or a sign.
  375.             ulong result = 0;
  376.            
  377.             if (Char.IsDigit(value[0]) || value[0] == '-' || value[0] == '+') {
  378.                 Type underlyingType = GetUnderlyingType(enumType);
  379.                 object temp;
  380.                
  381.                 try {
  382.                     temp = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
  383.                     return ToObject(enumType, temp);
  384.                 }
  385.                 catch (FormatException) {
  386.                     // We need to Parse this a String instead. There are cases
  387.                     // when you tlbimp enums that can have values of the form "3D".
  388.                     // Don't fix this code.
  389.                 }
  390.             }
  391.            
  392.             string[] values = value.Split(enumSeperatorCharArray);
  393.            
  394.             // Find the field.Lets assume that these are always static classes because the class is
  395.             // an enum.
  396.             HashEntry hashEntry = GetHashEntry(enumType);
  397.             string[] names = hashEntry.names;
  398.            
  399.             for (int i = 0; i < values.Length; i++) {
  400.                 values[i] = values[i].Trim();
  401.                 // We need to remove whitespace characters
  402.                 bool success = false;
  403.                
  404.                 for (int j = 0; j < names.Length; j++) {
  405.                     if (ignoreCase) {
  406.                         if (String.Compare(names[j], values[i], StringComparison.OrdinalIgnoreCase) != 0)
  407.                             continue;
  408.                     }
  409.                     else {
  410.                         if (!names[j].Equals(values[i]))
  411.                             continue;
  412.                     }
  413.                    
  414.                     ulong item = hashEntry.values[j];
  415.                    
  416.                     result |= item;
  417.                     success = true;
  418.                     break;
  419.                 }
  420.                
  421.                 if (!success)
  422.                    
  423.                     // Not found, throw an argument exception.
  424.                     throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumValueNotFound"), value));
  425.             }
  426.            
  427.             return ToObject(enumType, result);
  428.         }
  429.        
  430.         [System.Runtime.InteropServices.ComVisible(true)]
  431.         public static Type GetUnderlyingType(Type enumType)
  432.         {
  433.             if (enumType == null)
  434.                 throw new ArgumentNullException("enumType");
  435.            
  436.             // Make this function working for EnumBuilder. JScript uses it.
  437.             if (enumType is EnumBuilder) {
  438.                 return ((EnumBuilder)enumType).UnderlyingSystemType;
  439.             }
  440.            
  441.             if (!(enumType is RuntimeType))
  442.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  443.            
  444.             if (!enumType.IsEnum)
  445.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  446.            
  447.             return InternalGetUnderlyingType(enumType);
  448.         }
  449.        
  450.         [System.Runtime.InteropServices.ComVisible(true)]
  451.         public static Array GetValues(Type enumType)
  452.         {
  453.             if (enumType == null)
  454.                 throw new ArgumentNullException("enumType");
  455.            
  456.             if (!(enumType is RuntimeType))
  457.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  458.            
  459.             if (!enumType.IsEnum)
  460.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  461.            
  462.             // Get all of the values
  463.             ulong[] values = GetHashEntry(enumType).values;
  464.            
  465.             // Create a generic Array
  466.             Array ret = Array.CreateInstance(enumType, values.Length);
  467.            
  468.             for (int i = 0; i < values.Length; i++) {
  469.                 object val = ToObject(enumType, values[i]);
  470.                
  471.                 ret.SetValue(val, i);
  472.             }
  473.            
  474.             return ret;
  475.         }
  476.        
  477.         [System.Runtime.InteropServices.ComVisible(true)]
  478.         public static string GetName(Type enumType, object value)
  479.         {
  480.             if (enumType == null)
  481.                 throw new ArgumentNullException("enumType");
  482.            
  483.             if (!(enumType is RuntimeType))
  484.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  485.            
  486.             if (!enumType.IsEnum)
  487.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  488.            
  489.             if (value == null)
  490.                 throw new ArgumentNullException("value");
  491.            
  492.             Type valueType = value.GetType();
  493.            
  494.             if (valueType.IsEnum || valueType == intType || valueType == typeof(short) || valueType == typeof(ushort) || valueType == typeof(byte) || valueType == typeof(sbyte) || valueType == typeof(uint) || valueType == typeof(long) || valueType == typeof(ulong))
  495.                 return InternalGetValueAsString(enumType, value);
  496.            
  497.             throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
  498.         }
  499.        
  500.         [System.Runtime.InteropServices.ComVisible(true)]
  501.         public static string[] GetNames(Type enumType)
  502.         {
  503.             if (enumType == null)
  504.                 throw new ArgumentNullException("enumType");
  505.            
  506.             if (!(enumType is RuntimeType))
  507.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  508.            
  509.             if (!enumType.IsEnum)
  510.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  511.            
  512.             // Get all of the Field names
  513.             string[] ret = GetHashEntry(enumType).names;
  514.            
  515.             // Make a copy since we can't hand out the same array since users can modify them
  516.             string[] retVal = new string[ret.Length];
  517.            
  518.             Array.Copy(ret, retVal, ret.Length);
  519.             return retVal;
  520.         }
  521.        
  522.         [System.Runtime.InteropServices.ComVisible(true)]
  523.         public static object ToObject(Type enumType, object value)
  524.         {
  525.             if (value == null)
  526.                 throw new ArgumentNullException("value");
  527.            
  528.             // Delegate rest of error checking to the other functions
  529.             TypeCode typeCode = Convert.GetTypeCode(value);
  530.            
  531.             switch (typeCode) {
  532.                 case TypeCode.Int32:
  533.                     return ToObject(enumType, (int)value);
  534.                 case TypeCode.SByte:
  535.                    
  536.                     return ToObject(enumType, (sbyte)value);
  537.                 case TypeCode.Int16:
  538.                    
  539.                     return ToObject(enumType, (short)value);
  540.                 case TypeCode.Int64:
  541.                    
  542.                     return ToObject(enumType, (long)value);
  543.                 case TypeCode.UInt32:
  544.                    
  545.                     return ToObject(enumType, (uint)value);
  546.                 case TypeCode.Byte:
  547.                    
  548.                     return ToObject(enumType, (byte)value);
  549.                 case TypeCode.UInt16:
  550.                    
  551.                     return ToObject(enumType, (ushort)value);
  552.                 case TypeCode.UInt64:
  553.                    
  554.                     return ToObject(enumType, (ulong)value);
  555.                 default:
  556.                    
  557.                     // All unsigned types will be directly cast
  558.                     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
  559.                     break;
  560.             }
  561.         }
  562.        
  563.         [System.Runtime.InteropServices.ComVisible(true)]
  564.         public static bool IsDefined(Type enumType, object value)
  565.         {
  566.             if (enumType == null)
  567.                 throw new ArgumentNullException("enumType");
  568.            
  569.             if (!(enumType is RuntimeType))
  570.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  571.            
  572.             if (!enumType.IsEnum)
  573.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  574.            
  575.             if (value == null)
  576.                 throw new ArgumentNullException("value");
  577.            
  578.             // Check if both of them are of the same type
  579.             Type valueType = value.GetType();
  580.            
  581.             if (!(valueType is RuntimeType))
  582.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "valueType");
  583.            
  584.             Type underlyingType = GetUnderlyingType(enumType);
  585.            
  586.             // If the value is an Enum then we need to extract the underlying value from it
  587.             if (valueType.IsEnum) {
  588.                 Type valueUnderlyingType = GetUnderlyingType(valueType);
  589.                
  590.                 if (valueType != enumType)
  591.                     throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType"), valueType.ToString(), enumType.ToString()));
  592.                
  593.                 valueType = valueUnderlyingType;
  594.             }
  595.             // The value must be of the same type as the Underlying type of the Enum
  596.             else if ((valueType != underlyingType) && (valueType != stringType)) {
  597.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType"), valueType.ToString(), underlyingType.ToString()));
  598.             }
  599.            
  600.             // If String is passed in
  601.             if (valueType == stringType) {
  602.                 // Get all of the Fields
  603.                 string[] names = GetHashEntry(enumType).names;
  604.                
  605.                 for (int i = 0; i < names.Length; i++)
  606.                     if (names[i].Equals((string)value))
  607.                         return true;
  608.                
  609.                 return false;
  610.             }
  611.            
  612.             ulong[] values = GetHashEntry(enumType).values;
  613.            
  614.             // Look at the 8 possible enum base classes
  615.             if (valueType == intType || valueType == typeof(short) || valueType == typeof(ushort) || valueType == typeof(byte) || valueType == typeof(sbyte) || valueType == typeof(uint) || valueType == typeof(long) || valueType == typeof(ulong)) {
  616.                 ulong val = ToUInt64(value);
  617.                
  618.                 return (BinarySearch(values, val) >= 0);
  619.             }
  620.            
  621.             BCLDebug.Assert(false, "Unknown enum type");
  622.             throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  623.         }
  624.        
  625.         [System.Runtime.InteropServices.ComVisible(true)]
  626.         public static string Format(Type enumType, object value, string format)
  627.         {
  628.             if (enumType == null)
  629.                 throw new ArgumentNullException("enumType");
  630.            
  631.             if (!(enumType is RuntimeType))
  632.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  633.            
  634.             if (!enumType.IsEnum)
  635.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  636.            
  637.             if (value == null)
  638.                 throw new ArgumentNullException("value");
  639.            
  640.             if (format == null)
  641.                 throw new ArgumentNullException("format");
  642.            
  643.             // Check if both of them are of the same type
  644.             Type valueType = value.GetType();
  645.            
  646.             if (!(valueType is RuntimeType))
  647.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "valueType");
  648.            
  649.             Type underlyingType = GetUnderlyingType(enumType);
  650.            
  651.             // If the value is an Enum then we need to extract the underlying value from it
  652.             if (valueType.IsEnum) {
  653.                 Type valueUnderlyingType = GetUnderlyingType(valueType);
  654.                
  655.                 if (valueType != enumType)
  656.                     throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType"), valueType.ToString(), enumType.ToString()));
  657.                
  658.                 valueType = valueUnderlyingType;
  659.                 value = ((Enum)value).GetValue();
  660.             }
  661.             // The value must be of the same type as the Underlying type of the Enum
  662.             else if (valueType != underlyingType) {
  663.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumFormatUnderlyingTypeAndObjectMustBeSameType"), valueType.ToString(), underlyingType.ToString()));
  664.             }
  665.            
  666.             if (format.Length != 1) {
  667.                 // all acceptable format string are of length 1
  668.                 throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
  669.             }
  670.            
  671.             char formatCh = format[0];
  672.            
  673.             if (formatCh == 'D' || formatCh == 'd') {
  674.                 return value.ToString();
  675.             }
  676.            
  677.             if (formatCh == 'X' || formatCh == 'x') {
  678.                 // Retrieve the value from the field.
  679.                 return InternalFormattedHexString(value);
  680.             }
  681.            
  682.             if (formatCh == 'G' || formatCh == 'g') {
  683.                 return InternalFormat(enumType, value);
  684.             }
  685.            
  686.             if (formatCh == 'F' || formatCh == 'f') {
  687.                 return InternalFlagsFormat(enumType, value);
  688.             }
  689.            
  690.             throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
  691.         }
  692.        
  693.         #endregion
  694.        
  695.         #region Definitions
  696.         private class HashEntry
  697.         {
  698.             // Each entry contains a list of sorted pair of enum field names and values, sorted by values
  699.             public HashEntry(string[] names, ulong[] values)
  700.             {
  701.                 this.names = names;
  702.                 this.values = values;
  703.             }
  704.            
  705.             public string[] names;
  706.             public ulong[] values;
  707.         }
  708.         #endregion
  709.        
  710.         #region Private Methods
  711.         private object GetValue()
  712.         {
  713.             return InternalGetValue();
  714.         }
  715.        
  716.         private string ToHexString()
  717.         {
  718.             Type eT = this.GetType();
  719.             FieldInfo thisField = GetValueField(eT);
  720.            
  721.             // Retrieve the value from the field.
  722.             return InternalFormattedHexString(((RtFieldInfo)thisField).InternalGetValue(this, false));
  723.             //return InternalFormattedHexString(((RuntimeFieldInfo)thisField).GetValue(this));
  724.         }
  725.        
  726.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  727.         private extern object InternalGetValue();
  728.        
  729.         #endregion
  730.        
  731.         #region Object Overrides
  732.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  733.         public override extern bool Equals(object obj);
  734.        
  735.         public override int GetHashCode()
  736.         {
  737.             return GetValue().GetHashCode();
  738.         }
  739.        
  740.         public override string ToString()
  741.         {
  742.             // Returns the value in a human readable format. For PASCAL style enums who's value maps directly the name of the field is returned.
  743.             // For PASCAL style enums who's values do not map directly the decimal value of the field is returned.
  744.             // For BitFlags (indicated by the Flags custom attribute): If for each bit that is set in the value there is a corresponding constant
  745.             //(a pure power of 2), then the OR string (ie "Red | Yellow") is returned. Otherwise, if the value is zero or if you can't create a string that consists of
  746.             // pure powers of 2 OR-ed together, you return a hex value
  747.             Type eT = this.GetType();
  748.             FieldInfo thisField = GetValueField(eT);
  749.            
  750.             // Retrieve the value from the field.
  751.             object value = ((RtFieldInfo)thisField).InternalGetValue(this, false);
  752.            
  753.             //Object value = ((RuntimeFieldInfo)thisField).GetValueInternal(this);
  754.             return InternalFormat(eT, value);
  755.         }
  756.         #endregion
  757.        
  758.         #region IFormattable
  759.         [Obsolete("The provider argument is not used. Please use ToString(String).")]
  760.         public string ToString(string format, IFormatProvider provider)
  761.         {
  762.             return ToString(format);
  763.         }
  764.         #endregion
  765.        
  766.         #region IComparable
  767.         public int CompareTo(object target)
  768.         {
  769.             const int retIncompatibleMethodTables = 2;
  770.             // indicates that the method tables did not match
  771.             const int retInvalidEnumType = 3;
  772.             // indicates that the enum was of an unknown/unsupported unerlying type
  773.             if (this == null)
  774.                 throw new NullReferenceException();
  775.            
  776.             int ret = InternalCompareTo(this, target);
  777.            
  778.             if (ret < retIncompatibleMethodTables) {
  779.                 // -1, 0 and 1 are the normal return codes
  780.                 return ret;
  781.             }
  782.             else if (ret == retIncompatibleMethodTables) {
  783.                 Type thisType = this.GetType();
  784.                 Type targetType = target.GetType();
  785.                
  786.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType"), targetType.ToString(), thisType.ToString()));
  787.             }
  788.             else {
  789.                 // assert valid return code (3)
  790.                 BCLDebug.Assert(ret == retInvalidEnumType, "Enum.InternalCompareTo return code was invalid");
  791.                
  792.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  793.             }
  794.         }
  795.         #endregion
  796.        
  797.         #region Public Methods
  798.         public string ToString(string format)
  799.         {
  800.             if (format == null || format.Length == 0)
  801.                 format = "G";
  802.            
  803.             if (String.Compare(format, "G", StringComparison.OrdinalIgnoreCase) == 0) {
  804.                 return ToString();
  805.                 // return InternalFormat(this.GetType(), this.GetValue());
  806.             }
  807.            
  808.             if (String.Compare(format, "D", StringComparison.OrdinalIgnoreCase) == 0)
  809.                 return this.GetValue().ToString();
  810.            
  811.             if (String.Compare(format, "X", StringComparison.OrdinalIgnoreCase) == 0)
  812.                 return this.ToHexString();
  813.            
  814.             if (String.Compare(format, "F", StringComparison.OrdinalIgnoreCase) == 0)
  815.                 return InternalFlagsFormat(this.GetType(), this.GetValue());
  816.            
  817.             throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
  818.         }
  819.        
  820.         [Obsolete("The provider argument is not used. Please use ToString().")]
  821.         public string ToString(IFormatProvider provider)
  822.         {
  823.             return ToString();
  824.         }
  825.        
  826.         #endregion
  827.        
  828.         #region IConvertable
  829.         public TypeCode GetTypeCode()
  830.         {
  831.             Type enumType = this.GetType();
  832.             Type underlyingType = GetUnderlyingType(enumType);
  833.            
  834.             if (underlyingType == typeof(Int32)) {
  835.                 return TypeCode.Int32;
  836.             }
  837.            
  838.             if (underlyingType == typeof(sbyte)) {
  839.                 return TypeCode.SByte;
  840.             }
  841.            
  842.             if (underlyingType == typeof(Int16)) {
  843.                 return TypeCode.Int16;
  844.             }
  845.            
  846.             if (underlyingType == typeof(Int64)) {
  847.                 return TypeCode.Int64;
  848.             }
  849.            
  850.             if (underlyingType == typeof(UInt32)) {
  851.                 return TypeCode.UInt32;
  852.             }
  853.            
  854.             if (underlyingType == typeof(byte)) {
  855.                 return TypeCode.Byte;
  856.             }
  857.            
  858.             if (underlyingType == typeof(UInt16)) {
  859.                 return TypeCode.UInt16;
  860.             }
  861.            
  862.             if (underlyingType == typeof(UInt64)) {
  863.                 return TypeCode.UInt64;
  864.             }
  865.            
  866.             BCLDebug.Assert(false, "Unknown underlying type.");
  867.             throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  868.         }
  869.        
  870.         /// <internalonly/>
  871.         bool IConvertible.ToBoolean(IFormatProvider provider)
  872.         {
  873.             return Convert.ToBoolean(GetValue(), CultureInfo.CurrentCulture);
  874.         }
  875.        
  876.         /// <internalonly/>
  877.         char IConvertible.ToChar(IFormatProvider provider)
  878.         {
  879.             return Convert.ToChar(GetValue(), CultureInfo.CurrentCulture);
  880.         }
  881.        
  882.         /// <internalonly/>
  883.         sbyte IConvertible.ToSByte(IFormatProvider provider)
  884.         {
  885.             return Convert.ToSByte(GetValue(), CultureInfo.CurrentCulture);
  886.         }
  887.        
  888.         /// <internalonly/>
  889.         byte IConvertible.ToByte(IFormatProvider provider)
  890.         {
  891.             return Convert.ToByte(GetValue(), CultureInfo.CurrentCulture);
  892.         }
  893.        
  894.         /// <internalonly/>
  895.         short IConvertible.ToInt16(IFormatProvider provider)
  896.         {
  897.             return Convert.ToInt16(GetValue(), CultureInfo.CurrentCulture);
  898.         }
  899.        
  900.         /// <internalonly/>
  901.         ushort IConvertible.ToUInt16(IFormatProvider provider)
  902.         {
  903.             return Convert.ToUInt16(GetValue(), CultureInfo.CurrentCulture);
  904.         }
  905.        
  906.         /// <internalonly/>
  907.         int IConvertible.ToInt32(IFormatProvider provider)
  908.         {
  909.             return Convert.ToInt32(GetValue(), CultureInfo.CurrentCulture);
  910.         }
  911.        
  912.         /// <internalonly/>
  913.         uint IConvertible.ToUInt32(IFormatProvider provider)
  914.         {
  915.             return Convert.ToUInt32(GetValue(), CultureInfo.CurrentCulture);
  916.         }
  917.        
  918.         /// <internalonly/>
  919.         long IConvertible.ToInt64(IFormatProvider provider)
  920.         {
  921.             return Convert.ToInt64(GetValue(), CultureInfo.CurrentCulture);
  922.         }
  923.        
  924.         /// <internalonly/>
  925.         ulong IConvertible.ToUInt64(IFormatProvider provider)
  926.         {
  927.             return Convert.ToUInt64(GetValue(), CultureInfo.CurrentCulture);
  928.         }
  929.        
  930.         /// <internalonly/>
  931.         float IConvertible.ToSingle(IFormatProvider provider)
  932.         {
  933.             return Convert.ToSingle(GetValue(), CultureInfo.CurrentCulture);
  934.         }
  935.        
  936.         /// <internalonly/>
  937.         double IConvertible.ToDouble(IFormatProvider provider)
  938.         {
  939.             return Convert.ToDouble(GetValue(), CultureInfo.CurrentCulture);
  940.         }
  941.        
  942.         /// <internalonly/>
  943.         decimal IConvertible.ToDecimal(IFormatProvider provider)
  944.         {
  945.             return Convert.ToDecimal(GetValue(), CultureInfo.CurrentCulture);
  946.         }
  947.        
  948.         /// <internalonly/>
  949.         DateTime IConvertible.ToDateTime(IFormatProvider provider)
  950.         {
  951.             throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_FromTo"), "Enum", "DateTime"));
  952.         }
  953.        
  954.         /// <internalonly/>
  955.         object IConvertible.ToType(Type type, IFormatProvider provider)
  956.         {
  957.             return Convert.DefaultToType((IConvertible)this, type, provider);
  958.         }
  959.         #endregion
  960.        
  961.         #region ToObject
  962.         [CLSCompliant(false)]
  963.         [System.Runtime.InteropServices.ComVisible(true)]
  964.         public static object ToObject(Type enumType, sbyte value)
  965.         {
  966.             if (enumType == null)
  967.                 throw new ArgumentNullException("enumType");
  968.             if (!(enumType is RuntimeType))
  969.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  970.             if (!enumType.IsEnum)
  971.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  972.             return InternalBoxEnum(enumType, value);
  973.         }
  974.         [System.Runtime.InteropServices.ComVisible(true)]
  975.         public static object ToObject(Type enumType, short value)
  976.         {
  977.             if (enumType == null)
  978.                 throw new ArgumentNullException("enumType");
  979.             if (!(enumType is RuntimeType))
  980.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  981.             if (!enumType.IsEnum)
  982.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  983.             return InternalBoxEnum(enumType, value);
  984.         }
  985.         [System.Runtime.InteropServices.ComVisible(true)]
  986.         public static object ToObject(Type enumType, int value)
  987.         {
  988.             if (enumType == null)
  989.                 throw new ArgumentNullException("enumType");
  990.             if (!(enumType is RuntimeType))
  991.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  992.             if (!enumType.IsEnum)
  993.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  994.             return InternalBoxEnum(enumType, value);
  995.         }
  996.         [System.Runtime.InteropServices.ComVisible(true)]
  997.         public static object ToObject(Type enumType, byte value)
  998.         {
  999.             if (enumType == null)
  1000.                 throw new ArgumentNullException("enumType");
  1001.             if (!(enumType is RuntimeType))
  1002.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  1003.             if (!enumType.IsEnum)
  1004.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  1005.             return InternalBoxEnum(enumType, value);
  1006.         }
  1007.         [CLSCompliant(false)]
  1008.         [System.Runtime.InteropServices.ComVisible(true)]
  1009.         public static object ToObject(Type enumType, ushort value)
  1010.         {
  1011.             if (enumType == null)
  1012.                 throw new ArgumentNullException("enumType");
  1013.             if (!(enumType is RuntimeType))
  1014.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  1015.             if (!enumType.IsEnum)
  1016.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  1017.             return InternalBoxEnum(enumType, value);
  1018.         }
  1019.         [CLSCompliant(false)]
  1020.         [System.Runtime.InteropServices.ComVisible(true)]
  1021.         public static object ToObject(Type enumType, uint value)
  1022.         {
  1023.             if (enumType == null)
  1024.                 throw new ArgumentNullException("enumType");
  1025.             if (!(enumType is RuntimeType))
  1026.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  1027.             if (!enumType.IsEnum)
  1028.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  1029.             return InternalBoxEnum(enumType, value);
  1030.         }
  1031.         [System.Runtime.InteropServices.ComVisible(true)]
  1032.         public static object ToObject(Type enumType, long value)
  1033.         {
  1034.             if (enumType == null)
  1035.                 throw new ArgumentNullException("enumType");
  1036.             if (!(enumType is RuntimeType))
  1037.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  1038.             if (!enumType.IsEnum)
  1039.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  1040.             return InternalBoxEnum(enumType, value);
  1041.         }
  1042.         [CLSCompliant(false)]
  1043.         [System.Runtime.InteropServices.ComVisible(true)]
  1044.         public static object ToObject(Type enumType, ulong value)
  1045.         {
  1046.             if (enumType == null)
  1047.                 throw new ArgumentNullException("enumType");
  1048.             if (!(enumType is RuntimeType))
  1049.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType");
  1050.             if (!enumType.IsEnum)
  1051.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
  1052.             return InternalBoxEnum(enumType, unchecked((long)value));
  1053.         }
  1054.         #endregion
  1055.     }
  1056. }

Developer Fusion