return !Object.ReferenceEquals (left, right);
}
- [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
- public virtual Type GetEnumUnderlyingType () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
-
- if (fields == null || fields.Length != 1)
- throw new ArgumentException ("An enum must have exactly one instance field", "enumType");
-
- return fields [0].FieldType;
- }
-
- [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
- public virtual string[] GetEnumNames () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
-
- string [] names = new string [fields.Length];
- if (0 != names.Length) {
- for (int i = 0; i < fields.Length; ++i)
- names [i] = fields [i].Name;
-
- var et = GetEnumUnderlyingType ();
- var values = Array.CreateInstance (et, names.Length);
- for (int i = 0; i < fields.Length; ++i)
- values.SetValue (fields [i].GetValue (null), i);
- MonoEnumInfo.SortEnums (et, values, names);
- }
-
- return names;
- }
-
static NotImplementedException CreateNIE () {
return new NotImplementedException ();
}
- public virtual Array GetEnumValues () {
- if (!IsEnum)
- throw new ArgumentException ("Type is not an enumeration", "enumType");
-
- throw CreateNIE ();
- }
-
- public virtual string GetEnumName (object value)
- {
- return Enum.GetName (this, value);
- }
-
- public virtual bool IsEnumDefined (object value)
- {
- return Enum.IsDefined (this, value);
- }
-
public static Type GetType (string typeName, Func<AssemblyName,Assembly> assemblyResolver, Func<Assembly,string,bool,Type> typeResolver)
{
return GetType (typeName, assemblyResolver, typeResolver, false, false);
return rootElementType;
}
+ #region Enum methods
+
+ // Default implementations of GetEnumNames, GetEnumValues, and GetEnumUnderlyingType
+ // Subclass of types can override these methods.
+
+ public virtual string[] GetEnumNames()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<String[]>() != null);
+
+ string[] names;
+ Array values;
+ GetEnumData(out names, out values);
+ return names;
+ }
+
+ // We don't support GetEnumValues in the default implementation because we cannot create an array of
+ // a non-runtime type. If there is strong need we can consider returning an object or int64 array.
+ public virtual Array GetEnumValues()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<Array>() != null);
+
+ throw new NotImplementedException();
+ }
+
+ // Returns the enum values as an object array.
+ private Array GetEnumRawConstantValues()
+ {
+ string[] names;
+ Array values;
+ GetEnumData(out names, out values);
+ return values;
+ }
+
+ // This will return enumValues and enumNames sorted by the values.
+ private void GetEnumData(out string[] enumNames, out Array enumValues)
+ {
+ Contract.Ensures(Contract.ValueAtReturn<String[]>(out enumNames) != null);
+ Contract.Ensures(Contract.ValueAtReturn<Array>(out enumValues) != null);
+
+ FieldInfo[] flds = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+
+ object[] values = new object[flds.Length];
+ string[] names = new string[flds.Length];
+
+ for (int i = 0; i < flds.Length; i++)
+ {
+ names[i] = flds[i].Name;
+ values[i] = flds[i].GetRawConstantValue();
+ }
+
+ // Insertion Sort these values in ascending order.
+ // We use this O(n^2) algorithm, but it turns out that most of the time the elements are already in sorted order and
+ // the common case performance will be faster than quick sorting this.
+ IComparer comparer = Comparer.Default;
+ for (int i = 1; i < values.Length; i++)
+ {
+ int j = i;
+ string tempStr = names[i];
+ object val = values[i];
+ bool exchanged = false;
+
+ // Since the elements are sorted we only need to do one comparision, we keep the check for j inside the loop.
+ while (comparer.Compare(values[j - 1], val) > 0)
+ {
+ names[j] = names[j - 1];
+ values[j] = values[j - 1];
+ j--;
+ exchanged = true;
+ if (j == 0)
+ break;
+ }
+
+ if (exchanged)
+ {
+ names[j] = tempStr;
+ values[j] = val;
+ }
+ }
+
+ enumNames = names;
+ enumValues = values;
+ }
+
+ public virtual Type GetEnumUnderlyingType()
+ {
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.Ensures(Contract.Result<Type>() != null);
+
+ FieldInfo[] fields = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (fields == null || fields.Length != 1)
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnum"), "enumType");
+
+ return fields[0].FieldType;
+ }
+
+ public virtual bool IsEnumDefined(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.EndContractBlock();
+
+ // Check if both of them are of the same type
+ Type valueType = value.GetType();
+
+ // If the value is an Enum then we need to extract the underlying value from it
+ if (valueType.IsEnum)
+ {
+ if (!valueType.IsEquivalentTo(this))
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType", valueType.ToString(), this.ToString()));
+
+ valueType = valueType.GetEnumUnderlyingType();
+ }
+
+ // If a string is passed in
+ if (valueType == typeof(string))
+ {
+ string[] names = GetEnumNames();
+ if (Array.IndexOf(names, value) >= 0)
+ return true;
+ else
+ return false;
+ }
+
+ // If an enum or integer value is passed in
+ if (Type.IsIntegerType(valueType))
+ {
+ Type underlyingType = GetEnumUnderlyingType();
+ // We cannot compare the types directly because valueType is always a runtime type but underlyingType might not be.
+ if (underlyingType.GetTypeCodeImpl() != valueType.GetTypeCodeImpl())
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), underlyingType.ToString()));
+
+ Array values = GetEnumRawConstantValues();
+ return (BinarySearch(values, value) >= 0);
+ }
+ else if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
+ {
+ // if at this point the value type is not an integer type, then its type doesn't match the enum type
+ // NetCF used to throw an argument exception in this case
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), GetEnumUnderlyingType()));
+ }
+ else
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
+ }
+ }
+
+ public virtual string GetEnumName(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (!IsEnum)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
+ Contract.EndContractBlock();
+
+ Type valueType = value.GetType();
+
+ if (!(valueType.IsEnum || Type.IsIntegerType(valueType)))
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
+
+ Array values = GetEnumRawConstantValues();
+ int index = BinarySearch(values, value);
+
+ if (index >= 0)
+ {
+ string[] names = GetEnumNames();
+ return names[index];
+ }
+
+ return null;
+ }
+
+ // Convert everything to ulong then perform a binary search.
+ private static int BinarySearch(Array array, object value)
+ {
+ ulong[] ulArray = new ulong[array.Length];
+ for (int i = 0; i < array.Length; ++i)
+ ulArray[i] = Enum.ToUInt64(array.GetValue(i));
+
+ ulong ulValue = Enum.ToUInt64(value);
+
+ return Array.BinarySearch(ulArray, ulValue);
+ }
+
+ internal static bool IsIntegerType(Type t)
+ {
+ return (t == typeof(int) ||
+ t == typeof(short) ||
+ t == typeof(ushort) ||
+ t == typeof(byte) ||
+ t == typeof(sbyte) ||
+ t == typeof(uint) ||
+ t == typeof(long) ||
+ t == typeof(ulong) ||
+ t == typeof(char) ||
+ t == typeof(bool));
+ }
+
+ #endregion
+
#if !MOBILE
void _Type.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
{