5 // Miguel de Icaza (miguel@ximian.com)
6 // Nick Drochak (ndrochak@gol.com)
8 // (C) Ximian, Inc. http://www.ximian.com
10 // TODO: Mucho left to implement.
13 using System.Collections;
14 using System.Globalization;
15 using System.Runtime.CompilerServices;
18 internal struct MonoEnumInfo {
20 internal Array values;
21 internal string[] names;
23 [MethodImplAttribute(MethodImplOptions.InternalCall)]
24 private static extern void get_enum_info (Type enumType, out MonoEnumInfo info);
26 internal static void GetInfo (Type enumType, out MonoEnumInfo info) {
27 get_enum_info (enumType, out info);
28 Array.Sort (info.values, info.names);
33 public abstract class Enum : ValueType, IComparable, IConvertible {
35 // IConvertible methods Start -->
38 public TypeCode GetTypeCode () {
40 MonoEnumInfo.GetInfo (this.GetType (), out info);
41 return Type.GetTypeCode (info.utype);
44 bool IConvertible.ToBoolean (IFormatProvider provider)
46 return Convert.ToBoolean (get_value (), provider);
49 byte IConvertible.ToByte (IFormatProvider provider)
51 return Convert.ToByte (get_value (), provider);
54 char IConvertible.ToChar (IFormatProvider provider)
56 return Convert.ToChar (get_value (), provider);
59 DateTime IConvertible.ToDateTime (IFormatProvider provider)
61 return Convert.ToDateTime (get_value (), provider);
64 decimal IConvertible.ToDecimal (IFormatProvider provider)
66 return Convert.ToDecimal (get_value (), provider);
69 double IConvertible.ToDouble (IFormatProvider provider)
71 return Convert.ToDouble (get_value (), provider);
74 short IConvertible.ToInt16 (IFormatProvider provider)
76 return Convert.ToInt16 (get_value (), provider);
79 int IConvertible.ToInt32 (IFormatProvider provider)
81 return Convert.ToInt32 (get_value (), provider);
84 long IConvertible.ToInt64 (IFormatProvider provider)
86 return Convert.ToInt64 (get_value (), provider);
90 sbyte IConvertible.ToSByte (IFormatProvider provider)
92 return Convert.ToSByte (get_value (), provider);
95 float IConvertible.ToSingle (IFormatProvider provider)
97 return Convert.ToSingle (get_value (), provider);
101 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
103 throw new NotImplementedException ();
106 [CLSCompliant(false)]
107 public ushort ToUInt16 (IFormatProvider provider)
109 return Convert.ToUInt16 (get_value (), provider);
112 [CLSCompliant(false)]
113 uint IConvertible.ToUInt32 (IFormatProvider provider)
115 return Convert.ToUInt32 (get_value (), provider);
118 [CLSCompliant(false)]
119 ulong IConvertible.ToUInt64 (IFormatProvider provider)
121 return Convert.ToUInt64 (get_value (), provider);
124 // <-- End IConvertible methods
126 [MethodImplAttribute(MethodImplOptions.InternalCall)]
127 private extern object get_value ();
129 public static Array GetValues (Type enumType) {
130 if (null == enumType)
131 throw new ArgumentNullException ("enumType cannot be null.");
133 if (!enumType.IsEnum)
134 throw new ArgumentException ("enumType is not an Enum type.");
137 MonoEnumInfo.GetInfo (enumType, out info);
141 public static string[] GetNames (Type enumType) {
142 if (null == enumType)
143 throw new ArgumentNullException ("enumType cannot be null.");
145 if (!enumType.IsEnum)
146 throw new ArgumentException ("enumType is not an Enum type.");
149 MonoEnumInfo.GetInfo (enumType, out info);
153 public static string GetName (Type enumType, object value) {
154 if (null == enumType)
155 throw new ArgumentNullException ("enumType cannot be null.");
157 throw new ArgumentNullException ("value cannot be null.");
159 if (!enumType.IsEnum)
160 throw new ArgumentException ("enumType is not an Enum type.");
164 value = ToObject (enumType, value);
165 MonoEnumInfo.GetInfo (enumType, out info);
166 for (i = 0; i < info.values.Length; ++i) {
167 if (value.Equals (info.values.GetValue (i)))
168 return info.names [i];
173 public static bool IsDefined (Type enumType, object value) {
174 if (null == enumType)
175 throw new ArgumentNullException ("enumType cannot be null.");
177 throw new ArgumentNullException ("value cannot be null.");
179 if (!enumType.IsEnum)
180 throw new ArgumentException ("enumType is not an Enum type.");
183 MonoEnumInfo.GetInfo (enumType, out info);
185 Type vType = value.GetType ();
186 if (vType == typeof(String)) {
187 return ((IList)(info.names)).Contains (value);
188 } else if ((vType == info.utype) || (vType == enumType)) {
190 value = ToObject (enumType, value);
191 MonoEnumInfo.GetInfo (enumType, out info);
192 for (i = 0; i < info.values.Length; ++i) {
193 if (value.Equals (info.values.GetValue (i)))
198 throw new ArgumentException("The value parameter is not the correct type."
199 + "It must be type String or the same type as the underlying type"
206 public static Type GetUnderlyingType (Type enumType) {
207 if (null == enumType)
208 throw new ArgumentNullException ("enumType cannot be null.");
210 if (!enumType.IsEnum)
211 throw new ArgumentException ("enumType is not an Enum type.");
214 MonoEnumInfo.GetInfo (enumType, out info);
218 public static object Parse (Type enumType, string value)
220 // Note: Parameters are checked in the other overload
221 return Parse (enumType, value, false);
224 public static object Parse (Type enumType, string value, bool ignoreCase)
226 if (null == enumType)
227 throw new ArgumentNullException ("enumType cannot be null.");
230 throw new ArgumentNullException ("value cannot be null.");
232 if (!enumType.IsEnum)
233 throw new ArgumentException ("enumType is not an Enum type.");
235 if (String.Empty == value.Trim())
236 throw new ArgumentException ("value cannot be empty string.");
240 MonoEnumInfo.GetInfo (enumType, out info);
243 string[] names = value.Split(new char[] {','});
244 TypeCode typeCode = ((Enum) info.values.GetValue (0)).GetTypeCode ();
245 foreach (string name in names) {
247 for (i = 0; i < info.values.Length; ++i) {
248 if (String.Compare (name, info.names [i], ignoreCase) == 0) {
251 retVal |= (long)((byte)info.values.GetValue (i));
254 retVal |= (long)((SByte)info.values.GetValue (i));
257 retVal |= (long)((short)info.values.GetValue (i));
260 retVal |= (long)((int)info.values.GetValue (i));
263 retVal |= (long)info.values.GetValue (i);
265 case TypeCode.UInt16:
266 retVal |= (long)((UInt16)info.values.GetValue (i));
268 case TypeCode.UInt32:
269 retVal |= (long)((UInt32)info.values.GetValue (i));
271 case TypeCode.UInt64:
272 retVal |= (long)((UInt64)info.values.GetValue (i));
280 throw new ArgumentException ("The requested value was not found");
283 return ToObject(enumType, retVal);
287 /// Compares the enum value with another enum value of the same type.
292 public int CompareTo (object obj)
299 thisType = this.GetType();
300 if (obj.GetType() != thisType){
301 throw new ArgumentException(
302 "Object must be the same type as the "
303 + "enum. The type passed in was "
304 + obj.GetType().ToString()
305 + "; the enum type was "
306 + thisType.ToString() + ".");
309 object value1, value2;
311 value1 = this.get_value ();
312 value2 = ((Enum)obj).get_value();
314 return ((IComparable)value1).CompareTo (value2);
317 public override string ToString ()
319 return ToString ("G", null);
322 public string ToString (IFormatProvider provider)
324 return ToString ("G", provider);
327 public string ToString (String format)
329 return ToString (format, null);
333 public string ToString (String format, IFormatProvider provider)
335 // provider is not used for Enums
337 if (format == String.Empty || format == null){
340 return Format (this.GetType(), this.get_value (), format);
343 public static object ToObject(Type enumType, byte value)
345 return ToObject (enumType, (object)value);
348 public static object ToObject(Type enumType, short value)
350 return ToObject (enumType, (object)value);
352 public static object ToObject(Type enumType, int value)
354 return ToObject (enumType, (object)value);
356 public static object ToObject(Type enumType, long value)
358 return ToObject (enumType, (object)value);
361 [MethodImplAttribute(MethodImplOptions.InternalCall)]
362 public static extern object ToObject(Type enumType, object value);
364 [CLSCompliant(false)]
365 public static object ToObject(Type enumType, sbyte value)
367 return ToObject (enumType, (object)value);
369 [CLSCompliant(false)]
370 public static object ToObject(Type enumType, ushort value)
372 return ToObject (enumType, (object)value);
374 [CLSCompliant(false)]
375 public static object ToObject(Type enumType, uint value)
377 return ToObject (enumType, (object)value);
379 [CLSCompliant(false)]
380 public static object ToObject(Type enumType, ulong value)
382 return ToObject (enumType, (object)value);
385 public override bool Equals (object obj)
390 if (obj.GetType() != this.GetType())
393 object v1 = this.get_value ();
394 object v2 = ((Enum)obj).get_value ();
396 return v1.Equals (v2);
399 public override int GetHashCode ()
401 object v = this.get_value ();
402 return v.GetHashCode ();
406 public static string Format (Type enumType, object value, string format)
408 if (null == enumType)
409 throw new ArgumentNullException("enumType cannot be null");
411 throw new ArgumentNullException("value cannot be null");
413 throw new ArgumentNullException("format cannot be null");
415 if (!enumType.IsEnum)
416 throw new ArgumentException("enumType is not an Enum Type");
418 Type vType = value.GetType();
419 if (vType != enumType && vType != Enum.GetUnderlyingType(enumType))
420 throw new ArgumentException();
423 if (format.Length != 1)
424 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," +
425 "\"x\",\"F\",\"f\",\"D\" or \"d\".");
427 char formatChar = format [0];
428 if ((formatChar == 'G' || formatChar == 'g')
429 && Attribute.IsDefined(enumType, typeof(FlagsAttribute)))
433 switch (formatChar) {
436 retVal = GetName (enumType, value);
438 retVal = value.ToString();
442 retVal = value.ToString();
443 long xValue = Int64.Parse(retVal);
444 // FIXME: Not sure if padding should always be with precision
445 // 8, if it's culture specific, or what. This works for me.
446 retVal = xValue.ToString("x8");
450 retVal = value.ToString();
455 MonoEnumInfo.GetInfo (enumType, out info);
456 // This is ugly, yes. We need to handle the different integer
457 // types for enums. If someone else has a better idea, be my guest.
458 switch (((Enum)info.values.GetValue (0)).GetTypeCode()) {
460 byte byteFlag = (byte)value;
462 for (int i = info.values.Length-1; i>=0 && byteFlag != 0; i--) {
463 byteenumValue = (byte)info.values.GetValue (i);
464 if ((byteenumValue & byteFlag) == byteenumValue){
465 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
466 byteFlag -= byteenumValue;
471 SByte sbyteFlag = (SByte)value;
472 SByte sbyteenumValue;
473 for (int i = info.values.Length-1; i>=0 && sbyteFlag != 0; i--) {
474 sbyteenumValue = (SByte)info.values.GetValue (i);
475 if ((sbyteenumValue & sbyteFlag) == sbyteenumValue){
476 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
477 sbyteFlag -= sbyteenumValue;
482 short Int16Flag = (short)value;
483 short Int16enumValue;
484 for (int i = info.values.Length-1; i>=0 && Int16Flag != 0; i--) {
485 Int16enumValue = (short)info.values.GetValue (i);
486 if ((Int16enumValue & Int16Flag) == Int16enumValue){
487 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
488 Int16Flag -= Int16enumValue;
493 int Int32Flag = (int)value;
495 for (int i = info.values.Length-1; i>=0 && Int32Flag != 0; i--) {
496 Int32enumValue = (int)info.values.GetValue (i);
497 if ((Int32enumValue & Int32Flag) == Int32enumValue){
498 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
499 Int32Flag -= Int32enumValue;
504 long Int64Flag = (long)value;
506 for (int i = info.values.Length-1; i>=0 && Int64Flag != 0; i--) {
507 Int64enumValue = (long)info.values.GetValue (i);
508 if ((Int64enumValue & Int64Flag) == Int64enumValue){
509 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
510 Int64Flag -= Int64enumValue;
514 case TypeCode.UInt16:
515 UInt16 UInt16Flag = (UInt16)value;
516 UInt16 UInt16enumValue;
517 for (int i = info.values.Length-1; i>=0 && UInt16Flag != 0; i--) {
518 UInt16enumValue = (UInt16)info.values.GetValue (i);
519 if ((UInt16enumValue & UInt16Flag) == UInt16enumValue){
520 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
521 UInt16Flag -= UInt16enumValue;
525 case TypeCode.UInt32:
526 UInt32 UInt32Flag = (UInt32)value;
527 UInt32 UInt32enumValue;
528 for (int i = info.values.Length-1; i>=0 && UInt32Flag != 0; i--) {
529 UInt32enumValue = (UInt32)info.values.GetValue (i);
530 if ((UInt32enumValue & UInt32Flag) == UInt32enumValue){
531 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
532 UInt32Flag -= UInt32enumValue;
536 case TypeCode.UInt64:
537 UInt64 UInt64Flag = (UInt64)value;
538 UInt64 UInt64enumValue;
539 for (int i = info.values.Length-1; i>=0 && UInt64Flag != 0; i--) {
540 UInt64enumValue = (UInt64)info.values.GetValue (i);
541 if ((UInt64enumValue & UInt64Flag) == UInt64enumValue){
542 retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal;
543 UInt64Flag -= UInt64enumValue;
550 throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," +
551 "\"x\",\"F\",\"f\",\"D\" or \"d\".");