📄 typemanager.cs
字号:
/// of an interface. /// </summary> /// /// <remarks> /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to /// be IA, IB, IC. /// </remarks> public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces) { ArrayList new_ifaces = new ArrayList (); foreach (TypeExpr iface in base_interfaces){ Type itype = iface.ResolveType (ec); if (itype == null) return null; if (!new_ifaces.Contains (itype)) new_ifaces.Add (itype); Type [] implementing = itype.GetInterfaces (); foreach (Type imp in implementing){ if (!new_ifaces.Contains (imp)) new_ifaces.Add (imp); } } Type [] ret = new Type [new_ifaces.Count]; new_ifaces.CopyTo (ret, 0); return ret; } static PtrHashtable iface_cache = new PtrHashtable (); /// <summary> /// This function returns the interfaces in the type `t'. Works with /// both types and TypeBuilders. /// </summary> public static Type [] GetInterfaces (Type t) { Type [] cached = iface_cache [t] as Type []; if (cached != null) return cached; // // The reason for catching the Array case is that Reflection.Emit // will not return a TypeBuilder for Array types of TypeBuilder types, // but will still throw an exception if we try to call GetInterfaces // on the type. // // Since the array interfaces are always constant, we return those for // the System.Array // if (t.IsArray) t = TypeManager.array_type; if (t is TypeBuilder){ Type [] base_ifaces; if (t.BaseType == null) base_ifaces = NoTypes; else base_ifaces = GetInterfaces (t.BaseType); Type [] type_ifaces = (Type []) builder_to_ifaces [t]; if (type_ifaces == null) type_ifaces = NoTypes; int base_count = base_ifaces.Length; Type [] result = new Type [base_count + type_ifaces.Length]; base_ifaces.CopyTo (result, 0); type_ifaces.CopyTo (result, base_count); iface_cache [t] = result; return result; } else { Type[] ifaces = t.GetInterfaces (); iface_cache [t] = ifaces; return ifaces; } } // // gets the interfaces that are declared explicitly on t // public static Type [] GetExplicitInterfaces (TypeBuilder t) { return (Type []) builder_to_ifaces [t]; } /// <remarks> /// The following is used to check if a given type implements an interface. /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime. /// </remarks> public static bool ImplementsInterface (Type t, Type iface) { Type [] interfaces; // // FIXME OPTIMIZATION: // as soon as we hit a non-TypeBuiler in the interface // chain, we could return, as the `Type.GetInterfaces' // will return all the interfaces implement by the type // or its bases. // do { interfaces = GetInterfaces (t); if (interfaces != null){ foreach (Type i in interfaces){ if (i == iface) return true; } } t = t.BaseType; } while (t != null); return false; } static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat; // This is a custom version of Convert.ChangeType() which works // with the TypeBuilder defined types when compiling corlib. public static object ChangeType (object value, Type conversionType, out bool error) { IConvertible convert_value = value as IConvertible; if (convert_value == null){ error = true; return null; } // // We must use Type.Equals() here since `conversionType' is // the TypeBuilder created version of a system type and not // the system type itself. You cannot use Type.GetTypeCode() // on such a type - it'd always return TypeCode.Object. // error = false; try { if (conversionType.Equals (typeof (Boolean))) return (object)(convert_value.ToBoolean (nf_provider)); else if (conversionType.Equals (typeof (Byte))) return (object)(convert_value.ToByte (nf_provider)); else if (conversionType.Equals (typeof (Char))) return (object)(convert_value.ToChar (nf_provider)); else if (conversionType.Equals (typeof (DateTime))) return (object)(convert_value.ToDateTime (nf_provider)); else if (conversionType.Equals (TypeManager.decimal_type)) // typeof (Decimal))) return (object)(convert_value.ToDecimal (nf_provider)); else if (conversionType.Equals (typeof (Double))) return (object)(convert_value.ToDouble (nf_provider)); else if (conversionType.Equals (typeof (Int16))) return (object)(convert_value.ToInt16 (nf_provider)); else if (conversionType.Equals (typeof (Int32))) return (object)(convert_value.ToInt32 (nf_provider)); else if (conversionType.Equals (typeof (Int64))) return (object)(convert_value.ToInt64 (nf_provider)); else if (conversionType.Equals (typeof (SByte))) return (object)(convert_value.ToSByte (nf_provider)); else if (conversionType.Equals (typeof (Single))) return (object)(convert_value.ToSingle (nf_provider)); else if (conversionType.Equals (typeof (String))) return (object)(convert_value.ToString (nf_provider)); else if (conversionType.Equals (typeof (UInt16))) return (object)(convert_value.ToUInt16 (nf_provider)); else if (conversionType.Equals (typeof (UInt32))) return (object)(convert_value.ToUInt32 (nf_provider)); else if (conversionType.Equals (typeof (UInt64))) return (object)(convert_value.ToUInt64 (nf_provider)); else if (conversionType.Equals (typeof (Object))) return (object)(value); else error = true; } catch { error = true; } return null; } // // This is needed, because enumerations from assemblies // do not report their underlyingtype, but they report // themselves // public static Type EnumToUnderlying (Type t) { if (t == TypeManager.enum_type) return t; t = t.UnderlyingSystemType; if (!TypeManager.IsEnumType (t)) return t; if (t is TypeBuilder) { // slow path needed to compile corlib if (t == TypeManager.bool_type || t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.char_type || t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type || t == TypeManager.uint64_type) return t; } TypeCode tc = Type.GetTypeCode (t); switch (tc){ case TypeCode.Boolean: return TypeManager.bool_type; case TypeCode.Byte: return TypeManager.byte_type; case TypeCode.SByte: return TypeManager.sbyte_type; case TypeCode.Char: return TypeManager.char_type; case TypeCode.Int16: return TypeManager.short_type; case TypeCode.UInt16: return TypeManager.ushort_type; case TypeCode.Int32: return TypeManager.int32_type; case TypeCode.UInt32: return TypeManager.uint32_type; case TypeCode.Int64: return TypeManager.int64_type; case TypeCode.UInt64: return TypeManager.uint64_type; } throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName); } // // When compiling corlib and called with one of the core types, return // the corresponding typebuilder for that type. // public static Type TypeToCoreType (Type t) { if (RootContext.StdLib || (t is TypeBuilder)) return t; TypeCode tc = Type.GetTypeCode (t); switch (tc){ case TypeCode.Boolean: return TypeManager.bool_type; case TypeCode.Byte: return TypeManager.byte_type; case TypeCode.SByte: return TypeManager.sbyte_type; case TypeCode.Char: return TypeManager.char_type; case TypeCode.Int16: return TypeManager.short_type; case TypeCode.UInt16: return TypeManager.ushort_type; case TypeCode.Int32: return TypeManager.int32_type; case TypeCode.UInt32: return TypeManager.uint32_type; case TypeCode.Int64: return TypeManager.int64_type; case TypeCode.UInt64: return TypeManager.uint64_type; case TypeCode.Single: return TypeManager.float_type; case TypeCode.Double: return TypeManager.double_type; case TypeCode.String: return TypeManager.string_type; case TypeCode.Decimal: return TypeManager.decimal_type; default: if (t == typeof (void)) return TypeManager.void_type; if (t == typeof (object)) return TypeManager.object_type; if (t == typeof (System.Type)) return TypeManager.type_type; if (t == typeof (System.IntPtr)) return TypeManager.intptr_type; return t; } } /// <summary> /// Utility function that can be used to probe whether a type /// is managed or not. /// </summary> public static bool VerifyUnManaged (Type t, Location loc) { if (IsUnmanagedType (t)) return true; Report.Error (208, loc, "Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'", CSharpName (t)); return false; } /// <summary> /// Returns the name of the indexer in a given type. /// </summary> /// <remarks> /// The default is not always `Item'. The user can change this behaviour by /// using the IndexerNameAttribute in the container. /// For example, the String class indexer is named `Chars' not `Item' /// </remarks> public static string IndexerPropertyName (Type t) { if (t is TypeBuilder) { TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t); return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName; } System.Attribute attr = System.Attribute.GetCustomAttribute ( t, TypeManager.default_member_type); if (attr != null){ DefaultMemberAttribute dma = (DefaultMemberAttribute) attr; return dma.MemberName; } return TypeContainer.DefaultIndexerName; } static MethodInfo declare_local_method = null; public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t) { if (declare_local_method == null){ declare_local_method = typeof (ILGenerator).GetMethod ( "DeclareLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type [] { typeof (Type), typeof (bool)}, null); if (declare_local_method == null){ Report.Warning (-30, new Location (-1), "This version of the runtime does not support making pinned local variables. " + "This code may cause errors on a runtime with a moving GC"); return ig.DeclareLocal (t); } } return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true }); } // // Returns whether the array of memberinfos contains the given method // public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method) { Type [] new_args = TypeManager.GetArgumentTypes (new_method); foreach (MethodBase method in array) { if (method.Name != new_method.Name) continue; if (method is MethodInfo && new_method is MethodInfo) if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType) continue; Type [] old_args = TypeManager.GetArgumentTypes (method); int old_count = old_args.Length; int i; if (new_args.Length != old_count) continue; for (i = 0; i < old_count; i++){ if (old_args [i] != new_args [i]) break; } if (i != old_count) continue; return true; } return false; } // // We copy methods from `new_members' into `target_list' if the signature // for the method from in the new list does not exist in the target_list // // The name is assumed to be the same. // public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members) { if (target_list == null){ target_list = new ArrayList (); foreach (MemberInfo mi in new_members){ if (mi is MethodBase) target_list.Add (mi); } return target_list; } MemberInfo [] target_array = new MemberInfo [target_list.Count]; target_list.CopyTo (target_array, 0); foreach (MemberInfo mi in new_members){ MethodBase new_method = (MethodBase) mi; if (!ArrayContainsMethod (target_array, new_method)) target_list.Add (new_method); } return target_list; }#region MemberLookup implementation // // Whether we allow private members in the result (since FindMembers // uses NonPublic for both protected and private), we need to distinguish. // static internal bool FilterNone (MemberInfo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -