New tests.
[mono.git] / mcs / class / corlib / System / Type.cs
index 54753757b1ad3787b1410d2ccf7554292b6d7c61..a6d6f0d52f16dee34450ef32c1939198ccc7d6b1 100644 (file)
@@ -225,7 +225,11 @@ namespace System {
                        }
                }
 
-               public bool IsEnum {
+               public
+#if NET_4_0
+               virtual
+#endif
+               bool IsEnum {
                        get {
                                return IsSubclassOf (typeof (Enum));
                        }
@@ -327,7 +331,11 @@ namespace System {
                        }
                }
 
-               public bool IsSerializable {
+               public
+#if NET_4_0
+               virtual
+#endif
+               bool IsSerializable {
                        get {
                                if ((Attributes & TypeAttributes.Serializable) != 0)
                                        return true;
@@ -411,15 +419,41 @@ namespace System {
 
                public override bool Equals (object o)
                {
+#if NET_4_0
+                       return Equals (o as Type);
+#else
                        if (o == this)
                                return true;
+
                        Type me = UnderlyingSystemType;
                        if (me == null)
                                return false;
                        return me.EqualsInternal (o as Type);
+#endif
                }
 
-               public bool Equals (Type o) {
+#if NET_4_0
+               public virtual bool Equals (Type o)
+               {
+                       if ((object)o == this)
+                               return true;
+                       if ((object)o == null)
+                               return false;
+                       Type me = UnderlyingSystemType;
+                       if ((object)me == null)
+                               return false;
+
+                       o = o.UnderlyingSystemType;
+                       if ((object)o == null)
+                               return false;
+                       if ((object)o == this)
+                               return true;
+                       return me.EqualsInternal (o);
+               }               
+#else
+               public bool Equals (Type o)
+               {
+
                        if (o == this)
                                return true;
                        if (o == null)
@@ -429,7 +463,7 @@ namespace System {
                                return false;
                        return me.EqualsInternal (o.UnderlyingSystemType);
                }
-
+#endif
 #if NET_4_0
                [MonoTODO ("Implement it properly once 4.0 impl details are known.")]
                public static bool operator == (Type left, Type right)
@@ -442,6 +476,152 @@ namespace System {
                {
                        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 [] result = new string [fields.Length];
+                       for (int i = 0; i < fields.Length; ++i)
+                               result [i] = fields [i].Name;
+
+                       return result;
+               }
+
+               NotImplementedException CreateNIE () {
+                       return new NotImplementedException ();
+               }
+
+               public virtual Array GetEnumValues () {
+                       if (!IsEnum)
+                               throw new ArgumentException ("Type is not an enumeration", "enumType");
+
+                       throw CreateNIE ();
+               }
+
+               bool IsValidEnumType (Type type) {
+                       return (type.IsPrimitive && type != typeof (bool) && type != typeof (double) && type != typeof (float)) || type.IsEnum;
+               }
+
+               [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
+               public virtual string GetEnumName (object value) {
+                       if (value == null)
+                               throw new ArgumentException ("Value is null", "value");
+                       if (!IsValidEnumType (value.GetType ()))
+                               throw new ArgumentException ("Value is not the enum or a valid enum underlying type", "value");
+                       if (!IsEnum)
+                               throw new ArgumentException ("Type is not an enumeration", "enumType");
+
+                       object obj = null;
+                       var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+                       
+                       for (int i = 0; i < fields.Length; ++i) {
+                               var fv = fields [i].GetValue (null);
+                               if (obj == null) {
+                                       try {
+                                               //XXX we can't use 'this' as argument as it might be an UserType
+                                               obj = Enum.ToObject (fv.GetType (), value);
+                                       } catch (OverflowException) {
+                                               return null;
+                                       } catch (InvalidCastException) {
+                                               throw new ArgumentException ("Value is not valid", "value");
+                                       }
+                               }
+                               if (fv.Equals (obj))
+                                       return fields [i].Name;
+                       }
+
+                       return null;
+               }
+
+               [MonoInternalNote ("Reimplement this in MonoType for bonus speed")]
+               public virtual bool IsEnumDefined (object value) {
+                       if (value == null)
+                               throw new ArgumentException ("Value is null", "value");
+                       if (!IsEnum)
+                               throw new ArgumentException ("Type is not an enumeration", "enumType");
+
+                       Type vt = value.GetType ();
+                       if (!IsValidEnumType (vt) && vt != typeof (string))
+                               throw new InvalidOperationException ("Value is not the enum or a valid enum underlying type");
+
+                       var fields = GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+
+                       if (value is string) {
+                               for (int i = 0; i < fields.Length; ++i) {
+                                       if (fields [i].Name.Equals (value))
+                                               return true;
+                               }
+                       } else {
+                               if (vt != this && vt != GetEnumUnderlyingType ())
+                                       throw new ArgumentException ("Value is not the enum or a valid enum underlying type", "value");
+
+                               object obj = null;
+                               for (int i = 0; i < fields.Length; ++i) {
+                                       var fv = fields [i].GetValue (null);
+                                       if (obj == null) {
+                                               try {
+                                                       //XXX we can't use 'this' as argument as it might be an UserType
+                                                       obj = Enum.ToObject (fv.GetType (), value);
+                                               } catch (OverflowException) {
+                                                       return false;
+                                               } catch (InvalidCastException) {
+                                                       throw new ArgumentException ("Value is not valid", "value");
+                                               }
+                                       }
+                                       if (fv.Equals (obj))
+                                               return true;
+                               }
+                       }
+                       return false;
+               }
+       
+               public static Type GetType (string typeName, Func<AssemblyName,Assembly> assemblyResolver, Func<Assembly,string,bool,Type> typeResolver)
+               {
+                       return GetType (typeName, assemblyResolver, typeResolver, false, false);
+               }
+       
+               public static Type GetType (string typeName, Func<AssemblyName,Assembly> assemblyResolver, Func<Assembly,string,bool,Type> typeResolver, bool throwOnError)
+               {
+                       return GetType (typeName, assemblyResolver, typeResolver, throwOnError, false);
+               }
+       
+               public static Type GetType (string typeName, Func<AssemblyName,Assembly> assemblyResolver, Func<Assembly,string,bool,Type> typeResolver, bool throwOnError, bool ignoreCase)
+               {
+                       TypeSpec spec = TypeSpec.Parse (typeName);
+                       return spec.Resolve (assemblyResolver, typeResolver, throwOnError, ignoreCase);
+               }
+
+               public virtual bool IsSecurityTransparent
+               {
+                       get { throw CreateNIE (); }
+               }
+
+               public virtual bool IsSecurityCritical
+               {
+                       get { throw CreateNIE (); }
+               }
+
+               public virtual bool IsSecuritySafeCritical
+               {
+                       get { throw CreateNIE (); }
+               }
 #endif
                
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -499,12 +679,13 @@ namespace System {
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal extern static TypeCode GetTypeCodeInternal (Type type);
 
-               public static TypeCode GetTypeCode (Type type) {
+#if NET_4_0
+               protected virtual
+#endif
+               TypeCode GetTypeCodeImpl () {
+                       Type type = this;
                        if (type is MonoType)
                                return GetTypeCodeInternal (type);
-                       if (type == null)
-                               /* MS.NET returns this */
-                               return TypeCode.Empty;
 
                        type = type.UnderlyingSystemType;
 
@@ -514,6 +695,13 @@ namespace System {
                                return GetTypeCodeInternal (type);
                }
 
+               public static TypeCode GetTypeCode (Type type) {
+                       if (type == null)
+                               /* MS.NET returns this */
+                               return TypeCode.Empty;
+                       return type.GetTypeCodeImpl ();
+               }
+
                [MonoTODO("This operation is currently not supported by Mono")]
                public static Type GetTypeFromCLSID (Guid clsid)
                {
@@ -1050,23 +1238,18 @@ namespace System {
                                }
                        }
                        if ((memberType & MemberTypes.Property) != 0) {
-                               PropertyInfo[] c;
-                               int count = l.Count;
-                               Type ptype;
+                               PropertyInfo[] c = GetProperties (bindingAttr);
+
+
                                if (filter != null) {
-                                       ptype = this;
-                                       while ((l.Count == count) && (ptype != null)) {
-                                               c = ptype.GetProperties (bindingAttr);
-                                               foreach (MemberInfo m in c) {
-                                                       if (filter (m, filterCriteria))
-                                                               l.Add (m);
-                                               }
-                                               ptype = ptype.BaseType;
+                                       foreach (MemberInfo m in c) {
+                                               if (filter (m, filterCriteria))
+                                                       l.Add (m);
                                        }
                                } else {
-                                       c = GetProperties (bindingAttr);
                                        l.AddRange (c);
                                }
+
                        }
                        if ((memberType & MemberTypes.Event) != 0) {
                                EventInfo[] c = GetEvents (bindingAttr);
@@ -1163,6 +1346,11 @@ namespace System {
                        }
                }
 
+               internal virtual Type InternalResolve ()
+               {
+                       return UnderlyingSystemType;
+               }
+
                internal bool IsSystemType {
                        get {
                                return _impl.Value != IntPtr.Zero;