2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System / Enum.cs
blob49a4fd795a8333da2b22ef76891c94608399996a
1 //
2 // System.Enum.cs
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Nick Drochak (ndrochak@gol.com)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //
9 // (C) Ximian, Inc. http://www.ximian.com
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Globalization;
38 using System.Runtime.CompilerServices;
39 using System.Runtime.InteropServices;
41 namespace System
43 internal struct MonoEnumInfo
45 internal Type utype;
46 internal Array values;
47 internal string[] names;
48 internal Hashtable name_hash;
49 [ThreadStatic]
50 static Hashtable cache;
51 static Hashtable global_cache;
52 static object global_cache_monitor;
54 [MethodImplAttribute (MethodImplOptions.InternalCall)]
55 private static extern void get_enum_info (Type enumType, out MonoEnumInfo info);
58 // These comparers are needed because enumerations must be compared
59 // using unsigned values so that negative numbers can be looked up
60 // See bug: #371559
62 internal static SByteComparer sbyte_comparer = new SByteComparer ();
63 internal static ShortComparer short_comparer = new ShortComparer ();
64 internal static IntComparer int_comparer = new IntComparer ();
65 internal static LongComparer long_comparer = new LongComparer ();
67 internal class SByteComparer : IComparer, System.Collections.Generic.IComparer<sbyte>
69 public int Compare (object x, object y)
71 sbyte ix = (sbyte) x;
72 sbyte iy = (sbyte) y;
74 return ((byte) ix) - ((byte) iy);
77 public int Compare (sbyte ix, sbyte iy)
79 return ((byte) ix) - ((byte) iy);
83 internal class ShortComparer : IComparer, System.Collections.Generic.IComparer<short>
85 public int Compare (object x, object y)
87 short ix = (short) x;
88 short iy = (short) y;
90 return ((ushort) ix) - ((ushort) iy);
93 public int Compare (short ix, short iy)
95 return ((ushort) ix) - ((ushort) iy);
99 internal class IntComparer : IComparer, System.Collections.Generic.IComparer<int>
101 public int Compare (object x, object y)
103 int ix = (int) x;
104 int iy = (int) y;
106 if (ix == iy)
107 return 0;
109 if (((uint) ix) < ((uint) iy))
110 return -1;
111 return 1;
114 public int Compare (int ix, int iy)
116 if (ix == iy)
117 return 0;
119 if (((uint) ix) < ((uint) iy))
120 return -1;
121 return 1;
125 internal class LongComparer : IComparer, System.Collections.Generic.IComparer<long>
127 public int Compare (object x, object y)
129 long ix = (long) x;
130 long iy = (long) y;
132 if (ix == iy)
133 return 0;
134 if (((ulong) ix) < ((ulong) iy))
135 return -1;
136 return 1;
139 public int Compare (long ix, long iy)
141 if (ix == iy)
142 return 0;
143 if (((ulong) ix) < ((ulong) iy))
144 return -1;
145 return 1;
149 static MonoEnumInfo ()
151 global_cache_monitor = new object ();
152 global_cache = new Hashtable ();
155 static Hashtable Cache {
156 get {
157 if (cache == null) {
158 cache = new Hashtable ();
160 return cache;
163 private MonoEnumInfo (MonoEnumInfo other)
165 utype = other.utype;
166 values = other.values;
167 names = other.names;
168 name_hash = other.name_hash;
171 internal static void GetInfo (Type enumType, out MonoEnumInfo info)
173 /* First check the thread-local cache without locking */
174 if (Cache.ContainsKey (enumType)) {
175 info = (MonoEnumInfo) cache [enumType];
176 return;
178 /* Threads could die, so keep a global cache too */
179 lock (global_cache_monitor) {
180 if (global_cache.ContainsKey (enumType)) {
181 object boxedInfo = global_cache [enumType];
182 cache [enumType] = boxedInfo;
183 info = (MonoEnumInfo)boxedInfo;
184 return;
188 get_enum_info (enumType, out info);
190 IComparer ic = null;
191 if (info.values is int [])
192 ic = int_comparer;
193 else if (info.values is short [])
194 ic = short_comparer;
195 else if (info.values is sbyte [])
196 ic = sbyte_comparer;
197 else if (info.values is long [])
198 ic = long_comparer;
200 Array.Sort (info.values, info.names, ic);
201 if (info.names.Length > 50) {
202 info.name_hash = new Hashtable (info.names.Length);
203 for (int i = 0; i < info.names.Length; ++i)
204 info.name_hash [info.names [i]] = i;
206 MonoEnumInfo cached = new MonoEnumInfo (info);
207 lock (global_cache_monitor) {
208 global_cache [enumType] = cached;
213 [Serializable]
214 [ComVisible (true)]
215 public abstract class Enum : ValueType, IComparable, IConvertible, IFormattable
217 protected Enum ()
221 // IConvertible methods Start -->
222 public TypeCode GetTypeCode ()
224 return Type.GetTypeCode (GetUnderlyingType (this.GetType ()));
227 bool IConvertible.ToBoolean (IFormatProvider provider)
229 return Convert.ToBoolean (Value, provider);
232 byte IConvertible.ToByte (IFormatProvider provider)
234 return Convert.ToByte (Value, provider);
237 char IConvertible.ToChar (IFormatProvider provider)
239 return Convert.ToChar (Value, provider);
242 DateTime IConvertible.ToDateTime (IFormatProvider provider)
244 return Convert.ToDateTime (Value, provider);
247 decimal IConvertible.ToDecimal (IFormatProvider provider)
249 return Convert.ToDecimal (Value, provider);
252 double IConvertible.ToDouble (IFormatProvider provider)
254 return Convert.ToDouble (Value, provider);
257 short IConvertible.ToInt16 (IFormatProvider provider)
259 return Convert.ToInt16 (Value, provider);
262 int IConvertible.ToInt32 (IFormatProvider provider)
264 return Convert.ToInt32 (Value, provider);
267 long IConvertible.ToInt64 (IFormatProvider provider)
269 return Convert.ToInt64 (Value, provider);
272 sbyte IConvertible.ToSByte (IFormatProvider provider)
274 return Convert.ToSByte (Value, provider);
277 float IConvertible.ToSingle (IFormatProvider provider)
279 return Convert.ToSingle (Value, provider);
282 object IConvertible.ToType (Type targetType, IFormatProvider provider)
284 if (targetType == null)
285 throw new ArgumentNullException ("targetType");
286 if (targetType == typeof (string))
287 return ToString (provider);
288 return Convert.ToType (Value, targetType, provider, false);
291 ushort IConvertible.ToUInt16 (IFormatProvider provider)
293 return Convert.ToUInt16 (Value, provider);
296 uint IConvertible.ToUInt32 (IFormatProvider provider)
298 return Convert.ToUInt32 (Value, provider);
301 ulong IConvertible.ToUInt64 (IFormatProvider provider)
303 return Convert.ToUInt64 (Value, provider);
306 // <-- End IConvertible methods
308 [MethodImplAttribute (MethodImplOptions.InternalCall)]
309 private extern object get_value ();
311 // wrap the icall into a property so we don't hav to use the icall everywhere
312 private object Value {
313 get { return get_value (); }
316 [ComVisible (true)]
317 public static Array GetValues (Type enumType)
319 if (enumType == null)
320 throw new ArgumentNullException ("enumType");
322 if (!enumType.IsEnum)
323 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
325 MonoEnumInfo info;
326 MonoEnumInfo.GetInfo (enumType, out info);
327 return (Array) info.values.Clone ();
330 [ComVisible (true)]
331 public static string[] GetNames (Type enumType)
333 if (enumType == null)
334 throw new ArgumentNullException ("enumType");
336 if (!enumType.IsEnum)
337 throw new ArgumentException ("enumType is not an Enum type.");
339 MonoEnumInfo info;
340 MonoEnumInfo.GetInfo (enumType, out info);
341 return (string []) info.names.Clone ();
345 // The faster, non-boxing version. It must use the special MonoEnumInfo.xxx_comparers
346 // to ensure that we are perfoming bitwise compares, and not signed compares.
348 // It also tries to use the non-boxing version of the various Array.BinarySearch methods
350 static int FindPosition (object value, Array values)
352 int[] int_array = values as int[];
353 if (int_array != null)
354 return Array.BinarySearch (int_array, (int)value, MonoEnumInfo.int_comparer);
356 uint[] uint_array = values as uint [];
357 if (uint_array != null)
358 return Array.BinarySearch (uint_array, (uint)value);
360 short [] short_array = values as short [];
361 if (short_array != null)
362 return Array.BinarySearch (short_array, (short)value, MonoEnumInfo.short_comparer);
364 ushort [] ushort_array = values as ushort [];
365 if (ushort_array != null)
366 return Array.BinarySearch (ushort_array, (ushort)value);
368 sbyte [] sbyte_array = values as sbyte [];
369 if (sbyte_array != null)
370 return Array.BinarySearch (sbyte_array, (sbyte) value, MonoEnumInfo.sbyte_comparer);
372 byte [] byte_array = values as byte [];
373 if (byte_array != null)
374 return Array.BinarySearch (byte_array, (byte) value);
376 long [] long_array = values as long [];
377 if (long_array != null)
378 return Array.BinarySearch (long_array, (long) value, MonoEnumInfo.long_comparer);
380 ulong [] ulong_array = values as ulong [];
381 if (ulong_array != null)
382 return Array.BinarySearch (ulong_array, (ulong) value);
384 // This should never happen
385 return Array.BinarySearch (values, value);
388 [ComVisible (true)]
389 public static string GetName (Type enumType, object value)
391 if (enumType == null)
392 throw new ArgumentNullException ("enumType");
393 if (value == null)
394 throw new ArgumentNullException ("value");
396 if (!enumType.IsEnum)
397 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
399 MonoEnumInfo info;
400 value = ToObject (enumType, value);
401 MonoEnumInfo.GetInfo (enumType, out info);
403 int i = FindPosition (value, info.values);
404 return (i >= 0) ? info.names [i] : null;
407 [ComVisible (true)]
408 public static bool IsDefined (Type enumType, object value)
410 if (enumType == null)
411 throw new ArgumentNullException ("enumType");
412 if (value == null)
413 throw new ArgumentNullException ("value");
415 if (!enumType.IsEnum)
416 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
418 MonoEnumInfo info;
419 MonoEnumInfo.GetInfo (enumType, out info);
421 Type vType = value.GetType ();
422 if (vType == typeof(String)) {
423 return ((IList)(info.names)).Contains (value);
424 } else if ((vType == info.utype) || (vType == enumType)) {
425 value = ToObject (enumType, value);
426 MonoEnumInfo.GetInfo (enumType, out info);
428 return FindPosition (value, info.values) >= 0;
429 } else {
430 throw new ArgumentException("The value parameter is not the correct type."
431 + "It must be type String or the same type as the underlying type"
432 + "of the Enum.");
436 [MethodImplAttribute (MethodImplOptions.InternalCall)]
437 private static extern Type get_underlying_type (Type enumType);
439 [ComVisible (true)]
440 public static Type GetUnderlyingType (Type enumType)
442 if (enumType == null)
443 throw new ArgumentNullException ("enumType");
445 if (!enumType.IsEnum)
446 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
448 return get_underlying_type (enumType);
451 [ComVisible (true)]
452 public static object Parse (Type enumType, string value)
454 // Note: Parameters are checked in the other overload
455 return Parse (enumType, value, false);
458 private static int FindName (Hashtable name_hash, string [] names, string name, bool ignoreCase)
460 if (!ignoreCase) {
461 /* For enums with many values, use a hash table */
462 if (name_hash != null) {
463 object val = name_hash [name];
464 if (val != null)
465 return (int)val;
466 } else {
467 for (int i = 0; i < names.Length; ++i) {
468 if (name == names [i])
469 return i;
472 } else {
473 for (int i = 0; i < names.Length; ++i) {
474 if (String.Compare (name, names [i], ignoreCase, CultureInfo.InvariantCulture) == 0)
475 return i;
478 return -1;
481 // Helper function for dealing with [Flags]-style enums.
482 private static ulong GetValue (object value, TypeCode typeCode)
484 switch (typeCode) {
485 case TypeCode.Byte:
486 return (byte) value;
487 case TypeCode.SByte:
488 return (byte) ((sbyte) value);
489 case TypeCode.Int16:
490 return (ushort) ((short) value);
491 case TypeCode.Int32:
492 return (uint) ((int) value);
493 case TypeCode.Int64:
494 return (ulong) ((long) value);
495 case TypeCode.UInt16:
496 return (ushort) value;
497 case TypeCode.UInt32:
498 return (uint) value;
499 case TypeCode.UInt64:
500 return (ulong) value;
502 throw new ArgumentException ("typeCode is not a valid type code for an Enum");
505 private static char [] split_char = { ',' };
507 [ComVisible(true)]
508 public static object Parse (Type enumType, string value, bool ignoreCase)
510 if (enumType == null)
511 throw new ArgumentNullException ("enumType");
513 if (value == null)
514 throw new ArgumentNullException ("value");
516 if (!enumType.IsEnum)
517 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
519 value = value.Trim ();
520 if (value.Length == 0)
521 throw new ArgumentException ("An empty string is not considered a valid value.");
523 object result;
524 if (!Parse (enumType, value, ignoreCase, out result))
525 throw new ArgumentException (String.Format ("The requested value '{0}' was not found.", value));
527 return result;
530 static bool Parse<TEnum> (Type enumType, string value, bool ignoreCase, out TEnum result)
532 result = default (TEnum);
534 MonoEnumInfo info;
535 MonoEnumInfo.GetInfo (enumType, out info);
537 // is 'value' a named constant?
538 int loc = FindName (info.name_hash, info.names, value, ignoreCase);
539 if (loc >= 0) {
540 result = (TEnum) info.values.GetValue (loc);
541 return true;
544 TypeCode typeCode = ((Enum) info.values.GetValue (0)).GetTypeCode ();
546 // is 'value' a list of named constants?
547 if (value.IndexOf (',') != -1) {
548 string [] names = value.Split (split_char);
549 ulong retVal = 0;
550 for (int i = 0; i < names.Length; ++i) {
551 loc = FindName (info.name_hash, info.names, names [i].Trim (), ignoreCase);
552 if (loc < 0)
553 return false;
555 retVal |= GetValue (info.values.GetValue (loc), typeCode);
557 result = (TEnum) ToObject (enumType, retVal);
558 return true;
561 // is 'value' a number?
562 switch (typeCode) {
563 case TypeCode.SByte:
564 sbyte sb;
565 if (!SByte.TryParse (value, out sb))
566 return false;
567 result = (TEnum) ToObject (enumType, sb);
568 break;
569 case TypeCode.Byte:
570 byte b;
571 if (!Byte.TryParse (value, out b))
572 return false;
573 result = (TEnum) ToObject (enumType, b);
574 break;
575 case TypeCode.Int16:
576 short i16;
577 if (!Int16.TryParse (value, out i16))
578 return false;
579 result = (TEnum) ToObject (enumType, i16);
580 break;
581 case TypeCode.UInt16:
582 ushort u16;
583 if (!UInt16.TryParse (value, out u16))
584 return false;
585 result = (TEnum) ToObject (enumType, u16);
586 break;
587 case TypeCode.Int32:
588 int i32;
589 if (!Int32.TryParse (value, out i32))
590 return false;
591 result = (TEnum) ToObject (enumType, i32);
592 break;
593 case TypeCode.UInt32:
594 uint u32;
595 if (!UInt32.TryParse (value, out u32))
596 return false;
597 result = (TEnum) ToObject (enumType, u32);
598 break;
599 case TypeCode.Int64:
600 long i64;
601 if (!Int64.TryParse (value, out i64))
602 return false;
603 result = (TEnum) ToObject (enumType, i64);
604 break;
605 case TypeCode.UInt64:
606 ulong u64;
607 if (!UInt64.TryParse (value, out u64))
608 return false;
609 result = (TEnum) ToObject (enumType, u64);
610 break;
611 default:
612 break;
615 return true;
618 #if BOOTSTRAP_NET_4_0 || NET_4_0 || MOONLIGHT
619 public static bool TryParse<TEnum> (string value, out TEnum result) where TEnum : struct
621 return TryParse (value, false, out result);
624 public static bool TryParse<TEnum> (string value, bool ignoreCase, out TEnum result) where TEnum : struct
626 Type tenum_type = typeof (TEnum);
627 result = default (TEnum);
629 if (value == null || value.Trim ().Length == 0 || !tenum_type.IsEnum)
630 return false;
632 return Parse (tenum_type, value, ignoreCase, out result);
634 #endif
636 [MethodImplAttribute (MethodImplOptions.InternalCall)]
637 private extern int compare_value_to (object other);
639 /// <summary>
640 /// Compares the enum value with another enum value of the same type.
641 /// </summary>
643 /// <remarks/>
644 public int CompareTo (object target)
646 Type thisType;
648 if (target == null)
649 return 1;
651 thisType = this.GetType ();
652 if (target.GetType() != thisType) {
653 throw new ArgumentException (String.Format (
654 "Object must be the same type as the enum. The type passed in was {0}; the enum type was {1}.",
655 target.GetType(), thisType));
658 return compare_value_to (target);
661 public override string ToString ()
663 return ToString ("G");
666 [Obsolete("Provider is ignored, just use ToString")]
667 public string ToString (IFormatProvider provider)
669 return ToString ("G", provider);
672 public string ToString (String format)
674 if (format == String.Empty || format == null)
675 format = "G";
677 return Format (this.GetType (), this.Value, format);
680 [Obsolete("Provider is ignored, just use ToString")]
681 public string ToString (String format, IFormatProvider provider)
683 // provider is not used for Enums
685 if (format == String.Empty || format == null) {
686 format = "G";
688 return Format (this.GetType(), this.Value, format);
691 [ComVisible (true)]
692 public static object ToObject (Type enumType, byte value)
694 return ToObject (enumType, (object)value);
697 [ComVisible (true)]
698 public static object ToObject (Type enumType, short value)
700 return ToObject (enumType, (object)value);
703 [ComVisible (true)]
704 public static object ToObject (Type enumType, int value)
706 return ToObject (enumType, (object)value);
709 [ComVisible (true)]
710 public static object ToObject (Type enumType, long value)
712 return ToObject (enumType, (object)value);
715 [ComVisible (true)]
716 [MethodImplAttribute(MethodImplOptions.InternalCall)]
717 public static extern object ToObject (Type enumType, object value);
719 [ComVisible (true)]
720 [CLSCompliant (false)]
721 public static object ToObject (Type enumType, sbyte value)
723 return ToObject (enumType, (object)value);
726 [ComVisible (true)]
727 [CLSCompliant (false)]
728 public static object ToObject (Type enumType, ushort value)
730 return ToObject (enumType, (object)value);
733 [ComVisible (true)]
734 [CLSCompliant (false)]
735 public static object ToObject (Type enumType, uint value)
737 return ToObject (enumType, (object)value);
740 [ComVisible (true)]
741 [CLSCompliant (false)]
742 public static object ToObject (Type enumType, ulong value)
744 return ToObject (enumType, (object)value);
747 public override bool Equals (object obj)
749 return DefaultEquals (this, obj);
752 [MethodImplAttribute (MethodImplOptions.InternalCall)]
753 private extern int get_hashcode ();
755 public override int GetHashCode ()
757 return get_hashcode ();
760 private static string FormatSpecifier_X (Type enumType, object value, bool upper)
762 switch (Type.GetTypeCode (enumType)) {
763 case TypeCode.SByte:
764 return ((sbyte)value).ToString (upper ? "X2" : "x2");
765 case TypeCode.Byte:
766 return ((byte)value).ToString (upper ? "X2" : "x2");
767 case TypeCode.Int16:
768 return ((short)value).ToString (upper ? "X4" : "x4");
769 case TypeCode.UInt16:
770 return ((ushort)value).ToString (upper ? "X4" : "x4");
771 case TypeCode.Int32:
772 return ((int)value).ToString (upper ? "X8" : "x8");
773 case TypeCode.UInt32:
774 return ((uint)value).ToString (upper ? "X8" : "x8");
775 case TypeCode.Int64:
776 return ((long)value).ToString (upper ? "X16" : "x16");
777 case TypeCode.UInt64:
778 return ((ulong)value).ToString (upper ? "X16" : "x16");
779 default:
780 throw new Exception ("Invalid type code for enumeration.");
784 static string FormatFlags (Type enumType, object value)
786 string retVal = String.Empty;
787 MonoEnumInfo info;
788 MonoEnumInfo.GetInfo (enumType, out info);
789 string asString = value.ToString ();
790 if (asString == "0") {
791 retVal = GetName (enumType, value);
792 if (retVal == null)
793 retVal = asString;
794 return retVal;
796 // This is ugly, yes. We need to handle the different integer
797 // types for enums. If someone else has a better idea, be my guest.
798 switch (((Enum)info.values.GetValue (0)).GetTypeCode ()) {
799 case TypeCode.SByte: {
800 sbyte flags = (sbyte) value;
801 sbyte enumValue;
802 for (int i = info.values.Length - 1; i >= 0; i--) {
803 enumValue = (sbyte) info.values.GetValue (i);
804 if (enumValue == 0)
805 continue;
807 if ((flags & enumValue) == enumValue) {
808 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
809 flags -= enumValue;
812 if (flags != 0) return asString;
814 break;
815 case TypeCode.Byte: {
816 byte flags = (byte) value;
817 byte enumValue;
818 for (int i = info.values.Length - 1; i >= 0; i--) {
819 enumValue = (byte) info.values.GetValue (i);
820 if (enumValue == 0)
821 continue;
823 if ((flags & enumValue) == enumValue) {
824 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
825 flags -= enumValue;
828 if (flags != 0) return asString;
830 break;
831 case TypeCode.Int16: {
832 short flags = (short) value;
833 short enumValue;
834 for (int i = info.values.Length - 1; i >= 0; i--) {
835 enumValue = (short) info.values.GetValue (i);
836 if (enumValue == 0)
837 continue;
839 if ((flags & enumValue) == enumValue) {
840 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
841 flags -= enumValue;
844 if (flags != 0) return asString;
846 break;
847 case TypeCode.Int32: {
848 int flags = (int) value;
849 int enumValue;
850 for (int i = info.values.Length - 1; i >= 0; i--) {
851 enumValue = (int) info.values.GetValue (i);
852 if (enumValue == 0)
853 continue;
855 if ((flags & enumValue) == enumValue) {
856 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
857 flags -= enumValue;
860 if (flags != 0) return asString;
862 break;
863 case TypeCode.UInt16: {
864 ushort flags = (ushort) value;
865 ushort enumValue;
866 for (int i = info.values.Length - 1; i >= 0; i--) {
867 enumValue = (ushort) info.values.GetValue (i);
868 if (enumValue == 0)
869 continue;
871 if ((flags & enumValue) == enumValue) {
872 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
873 flags -= enumValue;
876 if (flags != 0) return asString;
878 break;
879 case TypeCode.UInt32: {
880 uint flags = (uint) value;
881 uint enumValue;
882 for (int i = info.values.Length - 1; i >= 0; i--) {
883 enumValue = (uint) info.values.GetValue (i);
884 if (enumValue == 0)
885 continue;
887 if ((flags & enumValue) == enumValue) {
888 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
889 flags -= enumValue;
892 if (flags != 0) return asString;
894 break;
895 case TypeCode.Int64: {
896 long flags = (long) value;
897 long enumValue;
898 for (int i = info.values.Length - 1; i >= 0; i--) {
899 enumValue = (long) info.values.GetValue (i);
900 if (enumValue == 0)
901 continue;
903 if ((flags & enumValue) == enumValue) {
904 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
905 flags -= enumValue;
908 if (flags != 0) return asString;
910 break;
911 case TypeCode.UInt64: {
912 ulong flags = (ulong) value;
913 ulong enumValue;
914 for (int i = info.values.Length - 1; i >= 0; i--) {
915 enumValue = (ulong) info.values.GetValue (i);
916 if (enumValue == 0)
917 continue;
919 if ((flags & enumValue) == enumValue) {
920 retVal = info.names[i] + (retVal == String.Empty ? String.Empty : ", ") + retVal;
921 flags -= enumValue;
924 if (flags != 0) return asString;
926 break;
929 if (retVal == String.Empty)
930 return asString;
932 return retVal;
935 [ComVisible (true)]
936 public static string Format (Type enumType, object value, string format)
938 if (enumType == null)
939 throw new ArgumentNullException ("enumType");
940 if (value == null)
941 throw new ArgumentNullException ("value");
942 if (format == null)
943 throw new ArgumentNullException ("format");
945 if (!enumType.IsEnum)
946 throw new ArgumentException ("enumType is not an Enum type.", "enumType");
948 Type vType = value.GetType();
949 Type underlyingType = Enum.GetUnderlyingType (enumType);
950 if (vType.IsEnum) {
951 if (vType != enumType)
952 throw new ArgumentException (string.Format(CultureInfo.InvariantCulture,
953 "Object must be the same type as the enum. The type" +
954 " passed in was {0}; the enum type was {1}.",
955 vType.FullName, enumType.FullName));
956 } else if (vType != underlyingType) {
957 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
958 "Enum underlying type and the object must be the same type" +
959 " or object. Type passed in was {0}; the enum underlying" +
960 " type was {1}.", vType.FullName, underlyingType.FullName));
963 if (format.Length != 1)
964 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," +
965 "\"x\",\"F\",\"f\",\"D\" or \"d\".");
967 char formatChar = format [0];
968 string retVal;
969 if ((formatChar == 'G' || formatChar == 'g')) {
970 if (!enumType.IsDefined (typeof(FlagsAttribute), false)) {
971 retVal = GetName (enumType, value);
972 if (retVal == null)
973 retVal = value.ToString();
975 return retVal;
978 formatChar = 'f';
981 if ((formatChar == 'f' || formatChar == 'F'))
982 return FormatFlags (enumType, value);
984 retVal = String.Empty;
985 switch (formatChar) {
986 case 'X':
987 retVal = FormatSpecifier_X (enumType, value, true);
988 break;
989 case 'x':
990 retVal = FormatSpecifier_X (enumType, value, false);
991 break;
992 case 'D':
993 case 'd':
994 if (underlyingType == typeof (ulong)) {
995 ulong ulongValue = Convert.ToUInt64 (value);
996 retVal = ulongValue.ToString ();
997 } else {
998 long longValue = Convert.ToInt64 (value);
999 retVal = longValue.ToString ();
1001 break;
1002 default:
1003 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," +
1004 "\"x\",\"F\",\"f\",\"D\" or \"d\".");
1006 return retVal;
1008 #if NET_4_0 || MOONLIGHT
1009 public bool HasFlag (Enum flag)
1011 ulong mvalue = Convert.ToUInt64 (get_value (), null);
1012 ulong fvalue = Convert.ToUInt64 (flag, null);
1014 return ((mvalue & fvalue) == fvalue);
1016 #endif