// // System.Enum.cs // // Authors: // Miguel de Icaza (miguel@ximian.com) // Nick Drochak (ndrochak@gol.com) // // (C) Ximian, Inc. http://www.ximian.com // // TODO: Mucho left to implement. // using System.Collections; using System.Globalization; using System.Runtime.CompilerServices; namespace System { internal struct MonoEnumInfo { internal Type utype; internal Array values; internal string[] names; [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void get_enum_info (Type enumType, out MonoEnumInfo info); internal static void GetInfo (Type enumType, out MonoEnumInfo info) { get_enum_info (enumType, out info); Array.Sort (info.values, info.names); } }; [MonoTODO] public abstract class Enum : ValueType, IComparable, IConvertible { // IConvertible methods Start --> [CLSCompliant(false)] public TypeCode GetTypeCode () { MonoEnumInfo info; MonoEnumInfo.GetInfo (this.GetType (), out info); return Type.GetTypeCode (info.utype); } bool IConvertible.ToBoolean (IFormatProvider provider) { return Convert.ToBoolean (get_value (), provider); } byte IConvertible.ToByte (IFormatProvider provider) { return Convert.ToByte (get_value (), provider); } char IConvertible.ToChar (IFormatProvider provider) { return Convert.ToChar (get_value (), provider); } DateTime IConvertible.ToDateTime (IFormatProvider provider) { return Convert.ToDateTime (get_value (), provider); } decimal IConvertible.ToDecimal (IFormatProvider provider) { return Convert.ToDecimal (get_value (), provider); } double IConvertible.ToDouble (IFormatProvider provider) { return Convert.ToDouble (get_value (), provider); } short IConvertible.ToInt16 (IFormatProvider provider) { return Convert.ToInt16 (get_value (), provider); } int IConvertible.ToInt32 (IFormatProvider provider) { return Convert.ToInt32 (get_value (), provider); } long IConvertible.ToInt64 (IFormatProvider provider) { return Convert.ToInt64 (get_value (), provider); } [CLSCompliant(false)] sbyte IConvertible.ToSByte (IFormatProvider provider) { return Convert.ToSByte (get_value (), provider); } float IConvertible.ToSingle (IFormatProvider provider) { return Convert.ToSingle (get_value (), provider); } [MonoTODO] object IConvertible.ToType (Type conversionType, IFormatProvider provider) { throw new NotImplementedException (); } [CLSCompliant(false)] public ushort ToUInt16 (IFormatProvider provider) { return Convert.ToUInt16 (get_value (), provider); } [CLSCompliant(false)] uint IConvertible.ToUInt32 (IFormatProvider provider) { return Convert.ToUInt32 (get_value (), provider); } [CLSCompliant(false)] ulong IConvertible.ToUInt64 (IFormatProvider provider) { return Convert.ToUInt64 (get_value (), provider); } // <-- End IConvertible methods [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern object get_value (); public static Array GetValues (Type enumType) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); MonoEnumInfo info; MonoEnumInfo.GetInfo (enumType, out info); return info.values; } public static string[] GetNames (Type enumType) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); MonoEnumInfo info; MonoEnumInfo.GetInfo (enumType, out info); return info.names; } public static string GetName (Type enumType, object value) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (null == value) throw new ArgumentNullException ("value cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); MonoEnumInfo info; int i; value = ToObject (enumType, value); MonoEnumInfo.GetInfo (enumType, out info); for (i = 0; i < info.values.Length; ++i) { if (value.Equals (info.values.GetValue (i))) return info.names [i]; } return null; } public static bool IsDefined (Type enumType, object value) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (null == value) throw new ArgumentNullException ("value cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); MonoEnumInfo info; MonoEnumInfo.GetInfo (enumType, out info); Type vType = value.GetType (); if (vType == typeof(String)) { return ((IList)(info.names)).Contains (value); } else if ((vType == info.utype) || (vType == enumType)) { int i; value = ToObject (enumType, value); MonoEnumInfo.GetInfo (enumType, out info); for (i = 0; i < info.values.Length; ++i) { if (value.Equals (info.values.GetValue (i))) return true; } return false; } else { throw new ArgumentException("The value parameter is not the correct type." + "It must be type String or the same type as the underlying type" + "of the Enum."); } } public static Type GetUnderlyingType (Type enumType) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); MonoEnumInfo info; MonoEnumInfo.GetInfo (enumType, out info); return info.utype; } public static object Parse (Type enumType, string value) { // Note: Parameters are checked in the other overload return Parse (enumType, value, false); } public static object Parse (Type enumType, string value, bool ignoreCase) { if (null == enumType) throw new ArgumentNullException ("enumType cannot be null."); if (null == value) throw new ArgumentNullException ("value cannot be null."); if (!enumType.IsEnum) throw new ArgumentException ("enumType is not an Enum type."); if (String.Empty == value.Trim()) throw new ArgumentException ("value cannot be empty string."); MonoEnumInfo info; int i; MonoEnumInfo.GetInfo (enumType, out info); long retVal = 0; string[] names = value.Split(new char[] {','}); TypeCode typeCode = ((Enum) info.values.GetValue (0)).GetTypeCode (); foreach (string name in names) { bool found = false; for (i = 0; i < info.values.Length; ++i) { if (String.Compare (name, info.names [i], ignoreCase) == 0) { switch (typeCode) { case TypeCode.Byte: retVal |= (long)((byte)info.values.GetValue (i)); break; case TypeCode.SByte: retVal |= (long)((SByte)info.values.GetValue (i)); break; case TypeCode.Int16: retVal |= (long)((short)info.values.GetValue (i)); break; case TypeCode.Int32: retVal |= (long)((int)info.values.GetValue (i)); break; case TypeCode.Int64: retVal |= (long)info.values.GetValue (i); break; case TypeCode.UInt16: retVal |= (long)((UInt16)info.values.GetValue (i)); break; case TypeCode.UInt32: retVal |= (long)((UInt32)info.values.GetValue (i)); break; case TypeCode.UInt64: retVal |= (long)((UInt64)info.values.GetValue (i)); break; } found = true; break; } } if (!found) throw new ArgumentException ("The requested value was not found"); } return ToObject(enumType, retVal); } /// /// Compares the enum value with another enum value of the same type. /// /// /// /// public int CompareTo (object obj) { Type thisType; if (obj == null) return 1; thisType = this.GetType(); if (obj.GetType() != thisType){ throw new ArgumentException( "Object must be the same type as the " + "enum. The type passed in was " + obj.GetType().ToString() + "; the enum type was " + thisType.ToString() + "."); } object value1, value2; value1 = this.get_value (); value2 = ((Enum)obj).get_value(); return ((IComparable)value1).CompareTo (value2); } public override string ToString () { return ToString ("G", null); } public string ToString (IFormatProvider provider) { return ToString ("G", provider); } public string ToString (String format) { return ToString (format, null); } [MonoTODO] public string ToString (String format, IFormatProvider provider) { // provider is not used for Enums if (format == String.Empty || format == null){ format = "G"; } return Format (this.GetType(), this.get_value (), format); } public static object ToObject(Type enumType, byte value) { return ToObject (enumType, (object)value); } public static object ToObject(Type enumType, short value) { return ToObject (enumType, (object)value); } public static object ToObject(Type enumType, int value) { return ToObject (enumType, (object)value); } public static object ToObject(Type enumType, long value) { return ToObject (enumType, (object)value); } [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern object ToObject(Type enumType, object value); [CLSCompliant(false)] public static object ToObject(Type enumType, sbyte value) { return ToObject (enumType, (object)value); } [CLSCompliant(false)] public static object ToObject(Type enumType, ushort value) { return ToObject (enumType, (object)value); } [CLSCompliant(false)] public static object ToObject(Type enumType, uint value) { return ToObject (enumType, (object)value); } [CLSCompliant(false)] public static object ToObject(Type enumType, ulong value) { return ToObject (enumType, (object)value); } public override bool Equals (object obj) { if (null == obj) return false; if (obj.GetType() != this.GetType()) return false; object v1 = this.get_value (); object v2 = ((Enum)obj).get_value (); return v1.Equals (v2); } public override int GetHashCode () { object v = this.get_value (); return v.GetHashCode (); } [MonoTODO] public static string Format (Type enumType, object value, string format) { if (null == enumType) throw new ArgumentNullException("enumType cannot be null"); if (null == value) throw new ArgumentNullException("value cannot be null"); if (null == format) throw new ArgumentNullException("format cannot be null"); if (!enumType.IsEnum) throw new ArgumentException("enumType is not an Enum Type"); Type vType = value.GetType(); if (vType != enumType && vType != Enum.GetUnderlyingType(enumType)) throw new ArgumentException(); if (format.Length != 1) throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," + "\"x\",\"F\",\"f\",\"D\" or \"d\"."); char formatChar = format [0]; if ((formatChar == 'G' || formatChar == 'g') && Attribute.IsDefined(enumType, typeof(FlagsAttribute))) formatChar = 'F'; string retVal = ""; switch (formatChar) { case 'G': case 'g': retVal = GetName (enumType, value); if (retVal == null) retVal = value.ToString(); break; case 'X': case 'x': retVal = value.ToString(); long xValue = Int64.Parse(retVal); // FIXME: Not sure if padding should always be with precision // 8, if it's culture specific, or what. This works for me. retVal = xValue.ToString("x8"); break; case 'D': case 'd': retVal = value.ToString(); break; case 'F': case 'f': MonoEnumInfo info; MonoEnumInfo.GetInfo (enumType, out info); // This is ugly, yes. We need to handle the different integer // types for enums. If someone else has a better idea, be my guest. switch (((Enum)info.values.GetValue (0)).GetTypeCode()) { case TypeCode.Byte: byte byteFlag = (byte)value; byte byteenumValue; for (int i = info.values.Length-1; i>=0 && byteFlag != 0; i--) { byteenumValue = (byte)info.values.GetValue (i); if ((byteenumValue & byteFlag) == byteenumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; byteFlag -= byteenumValue; } } break; case TypeCode.SByte: SByte sbyteFlag = (SByte)value; SByte sbyteenumValue; for (int i = info.values.Length-1; i>=0 && sbyteFlag != 0; i--) { sbyteenumValue = (SByte)info.values.GetValue (i); if ((sbyteenumValue & sbyteFlag) == sbyteenumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; sbyteFlag -= sbyteenumValue; } } break; case TypeCode.Int16: short Int16Flag = (short)value; short Int16enumValue; for (int i = info.values.Length-1; i>=0 && Int16Flag != 0; i--) { Int16enumValue = (short)info.values.GetValue (i); if ((Int16enumValue & Int16Flag) == Int16enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; Int16Flag -= Int16enumValue; } } break; case TypeCode.Int32: int Int32Flag = (int)value; int Int32enumValue; for (int i = info.values.Length-1; i>=0 && Int32Flag != 0; i--) { Int32enumValue = (int)info.values.GetValue (i); if ((Int32enumValue & Int32Flag) == Int32enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; Int32Flag -= Int32enumValue; } } break; case TypeCode.Int64: long Int64Flag = (long)value; long Int64enumValue; for (int i = info.values.Length-1; i>=0 && Int64Flag != 0; i--) { Int64enumValue = (long)info.values.GetValue (i); if ((Int64enumValue & Int64Flag) == Int64enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; Int64Flag -= Int64enumValue; } } break; case TypeCode.UInt16: UInt16 UInt16Flag = (UInt16)value; UInt16 UInt16enumValue; for (int i = info.values.Length-1; i>=0 && UInt16Flag != 0; i--) { UInt16enumValue = (UInt16)info.values.GetValue (i); if ((UInt16enumValue & UInt16Flag) == UInt16enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; UInt16Flag -= UInt16enumValue; } } break; case TypeCode.UInt32: UInt32 UInt32Flag = (UInt32)value; UInt32 UInt32enumValue; for (int i = info.values.Length-1; i>=0 && UInt32Flag != 0; i--) { UInt32enumValue = (UInt32)info.values.GetValue (i); if ((UInt32enumValue & UInt32Flag) == UInt32enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; UInt32Flag -= UInt32enumValue; } } break; case TypeCode.UInt64: UInt64 UInt64Flag = (UInt64)value; UInt64 UInt64enumValue; for (int i = info.values.Length-1; i>=0 && UInt64Flag != 0; i--) { UInt64enumValue = (UInt64)info.values.GetValue (i); if ((UInt64enumValue & UInt64Flag) == UInt64enumValue){ retVal = info.names[i] + (retVal == String.Empty ? "" : ", ") + retVal; UInt64Flag -= UInt64enumValue; } } break; } break; default: throw new FormatException ("Format String can be only \"G\",\"g\",\"X\"," + "\"x\",\"F\",\"f\",\"D\" or \"d\"."); } return retVal; } } }